使用 FIND & EXEC 在多个文件上执行需要文件名的 Perl 脚本
Using FIND & EXEC to execute a filename-required Perl script over multiple files
我在 unix / Linux 目录中存储了数百个 CSV 文件。他们的名字遵循以下格式: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 脚本进行编译。在其他来源中对 SO 进行了繁琐的研究,我得出以下结论......
find . -type -f -name '*.csv' -exec perl script.pl $('-printf "%f\n"') {} \;
但是这不起作用。而是输出多个“.xml”。毫无疑问,文件名(减去路径和扩展名)没有像上面的代码示例那样正确地传递给脚本。我尝试了多种变体 ...
$(-printf "%f\n"')
我知道我的问题就在这里。在许多情况下,我只是得到多个“.xml”。我觉得我正处于找到解决方案的风口浪尖。只是我不了解 -exec 之外的命令行功能的适当性。所以我想寻求任何帮助,看看是否有人知道解决方案。
该命令在执行任何其他操作之前先执行一个名为 -printf "%f\n"
的文件,这显然失败了。
我想你想要的是
find . -type -f -name '*.csv' -printf '%f[=10=]' | xargs -r0 ./script.pl
但这有两个问题:
- 你删除了路径,所以进行递归搜索没有任何意义(就像
find
默认情况下那样)。您已在评论中确认不需要进行递归搜索。
- 这仍然通过了您要删除的扩展程序。
因此,以下是您寻求的解决方案:
find . -maxdepth 1 -name '*.csv' -printf '%f[=11=]' |
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")'
第一个和最后一个将比其他两个更好地处理非常长的文件列表。
您可以像这样使用 GNU Parallel 非常简单地并行完成它们:
parallel --dry-run perl script.pl {.} ::: *csv
示例输出
perl script.pl 072019_foo
perl script.pl 122018_foo
如果看起来正确,请备份您的文件,然后 运行 再次备份,而无需 --dry-run
真正做到这一点。
您可以使用 parallel --bar ...
添加进度条
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', ) if /$re/;
}
find
命令的自然行为是递归到目录结构中。 OP 应在 post.
中指明是否需要递归
建议:熟悉3.5.3 Shell Parameter Expansion, How To Use Bash Parameter Substitution Like A Pro
我在 unix / Linux 目录中存储了数百个 CSV 文件。他们的名字遵循以下格式: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 脚本进行编译。在其他来源中对 SO 进行了繁琐的研究,我得出以下结论......
find . -type -f -name '*.csv' -exec perl script.pl $('-printf "%f\n"') {} \;
但是这不起作用。而是输出多个“.xml”。毫无疑问,文件名(减去路径和扩展名)没有像上面的代码示例那样正确地传递给脚本。我尝试了多种变体 ...
$(-printf "%f\n"')
我知道我的问题就在这里。在许多情况下,我只是得到多个“.xml”。我觉得我正处于找到解决方案的风口浪尖。只是我不了解 -exec 之外的命令行功能的适当性。所以我想寻求任何帮助,看看是否有人知道解决方案。
该命令在执行任何其他操作之前先执行一个名为 -printf "%f\n"
的文件,这显然失败了。
我想你想要的是
find . -type -f -name '*.csv' -printf '%f[=10=]' | xargs -r0 ./script.pl
但这有两个问题:
- 你删除了路径,所以进行递归搜索没有任何意义(就像
find
默认情况下那样)。您已在评论中确认不需要进行递归搜索。 - 这仍然通过了您要删除的扩展程序。
因此,以下是您寻求的解决方案:
find . -maxdepth 1 -name '*.csv' -printf '%f[=11=]' |
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")'
第一个和最后一个将比其他两个更好地处理非常长的文件列表。
您可以像这样使用 GNU Parallel 非常简单地并行完成它们:
parallel --dry-run perl script.pl {.} ::: *csv
示例输出
perl script.pl 072019_foo
perl script.pl 122018_foo
如果看起来正确,请备份您的文件,然后 运行 再次备份,而无需 --dry-run
真正做到这一点。
您可以使用 parallel --bar ...
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', ) if /$re/;
}
find
命令的自然行为是递归到目录结构中。 OP 应在 post.
建议:熟悉3.5.3 Shell Parameter Expansion, How To Use Bash Parameter Substitution Like A Pro