【问题标题】:Using FIND & EXEC to execute a filename-required Perl script over multiple files使用 FIND 和 EXEC 对多个文件执行文件名要求的 Perl 脚本
【发布时间】:2021-02-28 23:45:01
【问题描述】:

我有数百个 CSV 文件存储在 unix / Linux 目录中。他们的名字遵循以下格式:MMYYY_foo.csv。例如,

072019_foo.csv
122018_foo.csv

我正在尝试使用 Perl 脚本将它们单独编译并转换为 XML。该命令采用./script.pl MMMMYY_foo 的形式,因此在上面的示例中需要执行以下命令:

./script.pl 072019_foo
./script.pl 122018_foo

我不是在 UNIX / LINUX 中为每个文件单独执行 perl 脚本,而是尝试循环遍历文件,将它们传递给 perl 脚本进行编译。在其他来源中进行繁琐的研究后,我得出以下结论......

find . -type -f -name '*.csv' -exec perl script.pl $('-printf "%f\n"') {} \;

但是这不起作用。而是输出多个“.xml”。毫无疑问,文件名(减去路径和扩展名)没有像上面的代码示例那样正确传递给脚本。我尝试了多种变体...

$(-printf "%f\n"')

我知道这就是我的问题所在。在许多情况下,我只是得到多个“.xml”。我觉得我正处于寻找解决方案的风口浪尖。只是我不了解-exec之外的命令行功能的适当性。因此,我正在寻求有关是否有人知道解决方案的任何帮助。

【问题讨论】:

    标签: linux perl unix


    【解决方案1】:

    该命令在执行任何其他操作之前执行一个名为 -printf "%f\n" 的文件,这显然失败了。

    我认为你想要类似的东西

    find . -type -f -name '*.csv' -printf '%f\0' | xargs -r0 ./script.pl
    

    但这有两个问题:

    • 你去掉了路径,所以递归搜索没有任何意义(就像find默认的那样)。您已在 cmets 中确认不需要进行递归搜索。
    • 这仍然会传递您要删除的扩展名。

    因此,以下是您寻求的解决方案:

    find . -maxdepth 1 -name '*.csv' -printf '%f\0' |
       perl -0lpe's/\.[^.]*\z//' |
       xargs -r0 ./script.pl
    

    或者只是

    perl -0le'print s/\.[^.]*\z//r for @ARGV' -- *.csv |
       xargs -r0 ./script.pl
    

    或者只是

    perl -e'system("./script.pl", s/\.[^.]*\z//r) for @ARGV' -- *.csv
    

    或者只是

    perl -e'system("./script.pl", s/\.[^.]*\z//r) for glob("*.csv")'
    

    第一个和最后一个将比其他两个更好地处理非常长的文件列表。

    【讨论】:

      【解决方案2】:

      您可以使用 GNU Parallel 以非常简单的方式完成所有操作,如下所示:

      parallel --dry-run perl script.pl {.} ::: *csv
      

      样本输出

      perl script.pl 072019_foo
      perl script.pl 122018_foo
      

      如果看起来正确,请备份您的文件并在不使用 --dry-run 的情况下再次运行它以真正做到这一点。

      您可以使用parallel --bar ...添加进度条

      【讨论】:

      • 马克,感谢您的回答。遗憾的是,我没有 GNU Parallel,也没有能力将它添加到我公司的 IT 基础设施中。 :-/
      • 耻辱 - 在 CPU 越来越胖(更多内核)而不是更高(更多 GHz)的时代,它非常适用。顺便说一句,它实际上只是一个 Perl 脚本,就像其他任何脚本一样。
      【解决方案3】:

      OP 的find 样本表明需要处理目录中的所有和每个cvs 文件。

      假设不需要递归到目录结构。

      bash shell 的强大功能可用于此目的,文件扩展名在传递给脚本之前被剥离

      for f in *.cvs
      do
         ./script.pl ${f%.*}
      done
      

      如果此任务将定期重复,则上述脚本可以存储为 shell 脚本或创建的其他 perl 包装脚本

      #!/usr/bin/env perl
      
      use strict;
      use warnings;
      
      my $re = qr/(\d{6}_foo).cvs/;
      
      for ( glob('./*.cvs') ) {
              system('./script.pl', $1) if /$re/;
      }
      

      find 命令的自然行为是递归到目录结构。 OP 应该在帖子中说明递归是否可取。

      建议:熟悉3.5.3 Shell Parameter ExpansionHow To Use Bash Parameter Substitution Like A Pro

      【讨论】:

        猜你喜欢
        • 2011-11-21
        • 1970-01-01
        • 1970-01-01
        • 2017-01-23
        • 2015-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多