使用 FIND 和 EXEC 对多个文件执行文件名要求的 Perl 脚本
Posted
技术标签:
【中文标题】使用 FIND 和 EXEC 对多个文件执行文件名要求的 Perl 脚本【英文标题】:Using FIND & EXEC to execute a filename-required Perl script over multiple files 【发布时间】: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之外的命令行功能的适当性。因此,我正在寻求有关是否有人知道解决方案的任何帮助。
【问题讨论】:
【参考方案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/(\d6_foo).cvs/;
for ( glob('./*.cvs') )
system('./script.pl', $1) if /$re/;
find
命令的自然行为是递归到目录结构。 OP 应该在帖子中说明递归是否可取。
建议:熟悉3.5.3 Shell Parameter Expansion、How To Use Bash Parameter Substitution Like A Pro
【讨论】:
以上是关于使用 FIND 和 EXEC 对多个文件执行文件名要求的 Perl 脚本的主要内容,如果未能解决你的问题,请参考以下文章
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} ;