如何在 Perl 中使用带有管道的 Unix/AIX find 命令?

Posted

技术标签:

【中文标题】如何在 Perl 中使用带有管道的 Unix/AIX find 命令?【英文标题】:How to use the Unix/AIX find command with a pipe in Perl? 【发布时间】:2014-04-13 14:30:16 【问题描述】:

我正在尝试使用 Unix/AIX find 命令传送到 head 命令来返回目录中的第一个文件并将其分配给变量。但是,我的所有尝试都导致所有找到返回的文件都被分配给变量而没有应用 head 命令。

这是我的三个尝试:

Attempt 1: 
    $first_file = `/usr/bin/find $my_path -type f -name $potential_file_names | head -n1`;
Attempt 2: 
    $first_file = `/usr/bin/find $my_path -type f -name $potential_file_names '|' head -n1`;
Attempt 3:
    $first_file = `/usr/bin/find $my_path -type f -name $potential_file_names \\| head -n1`;

$potential_file_names 变量是一个带有通配符的字符串,用于返回目录中格式为“fileXXX.txt”的任何文件,其中“XXX”是一个三位数字。

$potential_file_names = 'file???.txt';

第一次尝试不起作用,因为 Perl 在返回错误“sh[2]: 0403-057.

第一次尝试输出:

file001.txt
file002.txt
file003.txt
file004.txt
file005.txt

第二次和第三次尝试也失败了。他们的错误是,“sh[2]: |: not found.”

第二次和第三次尝试的输出与第一次尝试相同。

是否可以使用通过管道传输的 find 命令返回我正在搜索的目录中的第一个文件(在我的例子中是“file001.txt”?

更新 我应该提到文件名可能不以 001 开头,所以我需要最旧的文件。这些文件是按顺序创建的,因此使用 find 和管道获取第一个文件到 head -n1 可以在脚本外部的命令行中使用。它必须是最旧/第一个文件,因为稍后我将在脚本中使用循环删除文件,这需要为每次迭代找到最旧/第一个文件。

谢谢。

【问题讨论】:

你能发布你的实际$potential_file_names吗?如果我用"*.csv" 尝试你的第一个版本,它就像一个魅力。 【参考方案1】:

好的,一些答案为后续编码人员创建了狗早餐,但确实指向了正确的方向,模块“使用文件::查找;”

我如何使用它的示例。 查找 (\&wanted, $directory); # 开始搜索路径

sub wanted 
    my $file = $File::Find::name;
    if  (-d $file ) 
      $directoryMap$file = $file;
      return;
    
    if (-z $file) 
       $zeroHash$file = 1;
       return;
    
    if ($file =~                 /(AAF|MXF|NSV|Ogg|RM|SVI|SMI|WMV)$/i) 
       my $size = -s $file;
       if ($size) 
          $hashmap$file = $size;
          return;
       
       else 
         $rejectMap$file = 1;
       return;
    
  
  else 
        $rejectMap$file = 1;
        return;
  
 

我使用它来查找具有特定扩展名的特定文件,然后将它们填充到哈希中 - 整个代码可以在我的 Perl 目录 (https://github.com/alexmac131/mediaData) 的 github 中找到。你可以把想要的东西改成对你有用的东西。

【讨论】:

【参考方案2】:

当有纯 Perl 等效项时,避免使用system 和反引号;您的代码将更具可移植性,并且您不必担心讨厌的 shell 引用问题。

如果您不关心子目录,可以使用readdir 获取特定目录中的文件列表:

#!/usr/bin/perl

use strict;
use warnings;

my $dir = 'foo';
opendir my $dh, $dir or die $!;

my @files = sort  -M "$dir/$b" <=> -M "$dir/$a" 
            grep  /^file\d3\.txt$/ && -f "$dir/$_"  readdir $dh;

closedir $dh;

print $files[0];

这将打印具有最早修改日期的文件的名称,尽管您当然可以使用another file test。


如果你还想在子目录中搜索,可以使用File::Find,这是一个核心模块:

use File::Find;
use File::Spec;

my @files;
my $dir = 'foo';
find(sub  push @files, $File::Find::name if /^file\d3\.txt$/ and -f $_; , $dir);

my @sorted = sort  -M $b <=> -M $a  @files;

print $sorted[0];

这会打印出修改日期最早的文件的路径

【讨论】:

路径不需要排序,或者至少它们不会使用管道传输到 head 的 find 命令,因为文件是按顺序创建的(默认情况下它们将被排序)。但是,我将删除文件,所以第一个文件并不总是 file001.txt。我更新了我的帖子,因为这最初并不清楚。 @user2063351 find 不按创建日期排序,至少在我的系统上没有。我不会依赖这种行为,因为它会因操作系统和文件系统而异,尤其是在执行诸如删除文件之类的危险操作时。我已更新我的答案以打印出修改日期最早的文件。【参考方案3】:

试试这样的:

    open EXE, qq/usr/bin/find $my_path -type f -name $potential_file_names | head -n1
                    or die qqError running command $!;
    my $file = <EXE>;
    close(EXE);

【讨论】:

以上是关于如何在 Perl 中使用带有管道的 Unix/AIX find 命令?的主要内容,如果未能解决你的问题,请参考以下文章

使用管道在 Perl 中将管道文件输出到 gzip 的 Python 等效项

如何在 perl 中读/写命名管道?

如果不重写Python / Perl脚本,我将如何在bash脚本中管道输出?

如何使用 Python 将标准输入/标准输出通过管道传输到 Perl 脚本

为啥子进程中的管道有时会中断,有时不会?

捕获 Perl 的 'system()' 的输出