【问题标题】:How to find/cut for only the filename from an output of ls -lrt in Perl如何仅从 Perl 中 ls -lrt 的输出中查找/剪切文件名
【发布时间】:2012-08-04 03:01:20
【问题描述】:

我想要ls -lrt 的输出中的文件名,但我找不到文件名。我使用了下面的命令,但它不起作用。

$cmd=' -rw-r--r-- 1 admin u19530 3506 Aug  7 03:34 sla.20120807033424.log';
my $result=`cut -d, -f9 $cmd`;
print "The file name is $result\n";

结果为空白。我需要文件名为sla.20120807033424.log


到目前为止,我已经尝试了以下代码,它适用于文件名。

代码

#!/usr/bin/perl
my $dir = <dir path>;
opendir (my $DH, $dir) or die "Error opening $dir: $!";
my %files = map { $_ => (stat("$dir/$_"))[9] } grep(! /^\.\.?$/, readdir($DH));
closedir($DH);
my @sorted_files = sort { $files{$b} <=> $files{$a} } (keys %files);
print "the file is $sorted_files[0] \n";

【问题讨论】:

  • 当您可以更有效地获取所有信息并且使用glob 和@987654327 没有任何讨厌的极端情况时,您到底为什么要解析像ls 的输出那样本质上无法解析的东西@函数?
  • 为什么不用perl的glob函数呢?解析ls 的输出有时会给你带来麻烦。 (如果您需要文件的元数据,还有stat。)如果您发现自己不得不在 Perl 脚本中使用cut,请阅读split
  • @JanHudec 他可能需要-rt 部分。 glob 不会那样做。
  • @Ariel:不会。但是stat(或-M)内置函数和很少的比较
  • 或者用更好的话说,你想实际实现什么? 解析供人类消费的文本很少是一个好主意,但如果你提供更多上下文,就有可能是更好的解决方案。

标签: linux perl cut


【解决方案1】:
use File::Find::Rule qw( );
use File::stat       qw( stat );
use List::Util       qw( reduce );

my ($oldest) =
   map $_ ? $_->[0] : undef,                              # 4. Get rid of stat data.
   reduce { $a->[1]->mtime < $b->[1]->mtime ? $a : $b }   # 3. Find one with oldest mtime.
   map [ $_, scalar(stat($_)) ],                          # 2. stat each file.
   File::Find::Rule                                       # 1. Find relevant files.
      ->maxdepth(1)                                       #       Don't recurse.
      ->file                                              #       Just plain files.
      ->in('.');                                          #       In whatever dir.

【讨论】:

  • @Ariel,完成。每条线都相当独立,所以这很容易。
  • @ikegami:你能告诉我你在这段代码中使用了哪个shebang语句
  • @pauler,我没用过。为什么你关心我的 Perl 安装在哪里?
【解决方案2】:

使用-l 会让你自己变得更难。这会做你想做的事

print((`ls -brt`)[0]);

但除非 Perl 不能提供你需要的东西,否则通常最好避免使用炮击,这很容易做到

print "$_\n" for (sort { -M $a <=> -M $b } glob "*")[0];

【讨论】:

  • 嗨,感谢所有建议。到目前为止,我已经尝试了以下代码,它适用于文件名:我正在共享以下代码:
  • #!/usr/bin/perl my $dir = ; opendir(my $DH, $dir) or die "Error opening $dir: $!";我的 %files = map { $_ => (stat("$dir/$_"))[9] } grep(! /^\.\.?$/, readdir($DH));关闭($DH);我的@sorted_files = sort { $files{$b} $files{$a} } (keys %files); print "文件是 $sorted_files[0] \n";
  • @pauler:这比我使用glob 的解决方案要长得多。为什么喜欢它?
  • Glob 并没有为我工作,glob 给了我最古老的 ls -rt o/p,但我需要的是来自 ls -lrt o/p 的最新文件
  • @pauler:我很抱歉。在这种情况下,只需颠倒排序即可。我已经更新了我的解决方案
【解决方案3】:

如果日志文件的名称在您的控制之下,即没有空格或其他特殊字符,那么可能是一个快速而肮脏的工作:

my $cmd=' -rw-r--r-- 1 admin u19530 3506 Aug  7 03:34 sla.20120807033424.log more more';
my @items = split ' ', $cmd;
print "log filename is : @items[8..$#items]";
print "\n";

【讨论】:

  • 感谢您的帮助,但您的回答假定文件不包含空白,您能否使用您的 Perl 技能(我没有)将其设为“元素 8 及以下所有内容” ?
  • 这只是针对 OP 特定情况的快速解决方案,他控制了一个日志文件系统。如果需要包含元素 8 及以下内容,请参阅我上面的编辑。
【解决方案4】:

-lrt 无法可靠地做到这一点 - 如果您愿意选择其他选项,您可以做到。

顺便说一句,即使没有 -l,您仍然可以使用 -rt 按逆时间排序。

另外,如果你必须使用 ls,你可能应该使用-b

【讨论】:

  • 对不起,我不同意。无法可靠地解析 ls 的输出,期间。你看,大多数 unice 都疯狂到允许在文件名中使用 换行符 字符,这会破坏任何不支持 NUL 终止的东西。
  • @JanHudec 当我说“其他选项”时,我指的是其他程序(替代方案)。但无论如何,-b 将有助于换行。
  • @JanHudec 我刚试了一下,换行符打印为\n
  • 你是对的,它会打印带有-b的转义序列。这使得它可以解析,但实际上需要做很多工作。
  • @JanHudec 当然——我同意这不是一个好方法,除非它是为了快速而肮脏的一次性。而且在我看来,是时候让你使用stat 发布一些 perl 代码了,这将包括反向时间排序:) OP 似乎擅离职守,但我会给你一个支持 :)
【解决方案5】:
my $cmd = ' -rw-r--r-- 1 admin u19530 3506 Aug  7 03:34 sla.20120807033424.log';

$cmd =~ / ( \S+) $/x or die "can't find filename in string " ;
my $filename = $1 ;

print $filename ; 

免责声明 - 如果文件名有空格并且可能在其他情况下,这将不起作用。 OP 将知道相关文件的命名约定。我同意有更强大的方法不使用ls -lrt

【讨论】:

    【解决方案6】:

    也许是这样的:

    ls -lrt *.log | perl -lane 'print $F[-1]'
    

    【讨论】:

    • 如果文件名包含一个空格怎么办? (如my resume.txt
    猜你喜欢
    • 2015-06-07
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 2013-03-30
    • 2017-06-21
    • 2015-08-16
    • 2012-03-22
    相关资源
    最近更新 更多