我可以使用 find 命令将参数传递给 perl 吗?

我可以使用 find 命令将参数传递给 perl 吗?

我有一个 perl 脚本

$ cat ~/script.pl
sub main {

    my ($file) = @_;

    <STUFF>

    }

}

foreach (@ARGV) {

    main($_);

}

我想执行目录下的~/script.pl每个文件。我可以使用以下命令获取文件列表.txt~/foo.txt~/foo

$ find ~/foo -type f -name \*.txt

我可以以某种方式使用此命令将这些文件传递到我的脚本吗?

答案1

是的,有多种方法可以使用命令来完成此find操作。我将按照我认为对理解您的情况很重要的顺序列出一些内容。

  1. 您的脚本似乎接受多个文件名参数,因此使用该find命令完成此操作的最有效且几乎通用的方法是:

    find ~/foo -type f -name \*.txt -exec perl ~/script.pl {} +
    

    这将使用尽可能多的找到的文件名参数执行您的脚本。如果需要处理所有文件名,您的脚本将被多次调用。请注意+该行末尾的 。

  2. 这是最原始、最通用的方法。这对于您的情况来说效率较低,因为它perl为找到的每个文件调用一次。此用法自Unix 的最早时代。请注意行末尾的转义分号 ( \;)(与+上面的相反)。

    find ~/foo -type f -name \*.txt -exec perl ~/script.pl {} \;
    
  3. -exec ... +将语法添加到之前find,发明该xargs命令是为了帮助提高处理文件名或其他参数列表时的效率。这与-exec ... +上面的示例几乎相同:

    find ~/foo -type f -name \*.txt -print | xargs perl ~/script.pl
    

    如果您的实现支持它,您应该使用-print0的选项find以及-0的参数xargs。这会导致find在参数字符串之间打印空字符,并防止xargs在除空字符之外的任何内容上分割参数。xargs如果您的文件名包含空格或其他一些特殊字符,这有助于防止错误地分割参数。

    使用-exec ... +语法通常是一个更好的主意,因为find这样可以将文件名直接放入脚本的参数列表中,从而消除一个过程,并避免通过管道传输到xargs.但是,xargs如果您需要对流程进行更多控制,则可能有优势。请参阅xargs手册页。

  4. 您还可以查看该find2perl命令,该命令采用相同的参数find并打印一个perl程序来执行相同的操作。然后,您可以将生成的perl代码合并到您的脚本中。在下面生成的脚本中,您将修改最后一行的旁边以调用您的函数而不是print.

    $ find2perl foo -type f -name \*.txt    # /*
    
    #[some preamble code removed for brevity]
    
    # Traverse desired filesystems
    File::Find::find({wanted => \&wanted}, 'foo');
    exit;
    
    sub wanted {
        my ($dev,$ino,$mode,$nlink,$uid,$gid);
    
        (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
        -f _ &&
        /^.*\.txt\z/s
        && print("$name\n");
    }   
    

答案2

正如其他答案所示 - 是的,你可以。

我会建议一个替代方案 - 不要这样做,而是使用内置的 perl File::Find- 它可以让你做基本上相同的事情,但是独立的。

例如:

#!/usr/bin/env perl
use strict;
use warnings;

use File::Find;

sub process {
    return unless -f;
    return unless m/\.txt$/; #regex style, not shell glob. 
    print "Found: Name of $_ as path $File::Find::name in $File::Find::dir\n"; 
}

find ( \&process, '~/foo' ); 

您可以对路径 ( ~/foo) 进行硬编码,也可以从@ARGV.

 find ( \&process, @ARGV ); #takes as many paths as you specify as args. 

答案3

是的,有-exec scriptName.sh {} \;结构

在你的具体情况下,那就是

find ~/foo -type f -name \*.txt -exec scriptName.sh {} \;

另一种方法是使用空分隔符将文件传递给xargs

这个例子直接取自 xargs 手册

 find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f

相关内容