如何链接命令“date -d @xxxxxx”和“find ./”?

如何链接命令“date -d @xxxxxx”和“find ./”?

我有一些目录,其名称是时间戳,自 1970 年 1 月 1 日起以毫秒为单位:

1439715011728
1439793321429
1439879712214
.
.

我需要一个像这样的输出:

1442039711    Sat Sep 12 08:35:11 CEST 2015
1442134211    Sun Sep 13 10:50:11 CEST 2015
1442212521    Mon Sep 14 08:35:21 CEST 2015
.
.

我可以通过命令列出所有目录:

find ./ -type d | cut -c 3-12

但我无法将输出放入下一个命令:date -d @xxxxxx并操纵输出。

我怎样才能做到这一点?

答案1

您走在正确的轨道上(对于更简单的解决方案,仅运行 2 或 3 个命令,请参见下文)。您应该使用*而不是./摆脱当前目录1,这在某种程度上简化了毫秒的切割,然后只需将结果通过管道传输到GNUparallelxargs2:

find * -type d | cut -c 1-10 | parallel date --date=@{} +%c

要得到

Sat 12 Sep 2015 08:35:11 CEST
Sun 13 Sep 2015 10:50:11 CEST
Mon 14 Sep 2015 08:35:21 CEST

并在其之前添加秒偏移量,如您的示例所示:

find * -type d | cut -c 1-10 | parallel 'echo "{} "  $(date --date=@{} +%c)'

或者:

find * -type d | cut -c 1-10 | xargs -I{} bash -c 'echo "{} "  $(date --date=@{} +%c)'

要得到:

1442039711  Sat 12 Sep 2015 08:35:11 CEST
1442134211  Sun 13 Sep 2015 10:50:11 CEST
1442212521  Mon 14 Sep 2015 08:35:21 CEST

然而,这样做更简单:

find * -type d -printf "@%.10f\n" | date -f - +'%s  %c'

这会再次为您提供相同的请求输出。

使用的缺点*是您的扩展受到命令行的限制,但优点是您可以按时间戳值对目录进行排序。如果目录数量有问题,请使用-mindepth 1,但会丢失顺序:

find ./ -mindepth 1 -type d -printf "@%.10f\n" | date -f - +'%s  %c'

sort并根据需要插入:

find ./ -mindepth 1 -type d -printf "@%.10f\n" | sort | date -f - +'%s  %c'

1这假设没有嵌套子目录,就像您的示例中的情况一样。您还可以使用²./ -mindepth 1代替*
²您可以按照 @hobbs 和 @don_crissti 的建议在此处替换parallelxargs -I{},它只是更冗长。 ³基于 Gilles 对使用dates 文件读取功能的回答

答案2

我会避免在循环中为每个文件运行多个命令。由于您已经在使用 GNUisms:

find . ! -name . -prune -type d |
  awk '{t = substr($0, 3, 10); print t, strftime("%a %b %d %T %Z %Y", t)}'

它只运行两个命令。strftime()是 GNU 特定的,例如date -d.

答案3

你已经拥有了:

find ./ -type d | cut -c 3-12

这可能会为您提供纪元格式的时间戳。现在添加一个 while 循环:

find ./ -type d | cut -c 3-12 | while read datestamp
do
    printf %s "$datestamp"
    date -d "@$datestamp"
done

但请注意,在某些 shell 中,该语法在子 shell 中获取 while 循环,这意味着如果您尝试在那里设置变量,那么一旦离开循环,该变量将不可见。为了解决这个问题,你需要稍微扭转一下局面:

while read datestamp
do
    printf %s "$datestamp"
    date -d "@$datestamp"
done < <(find ./ -type d | cut -c 3-12)

它将 放入find子 shell 中,并将 while 循环保留在主 shell 中。不过,仅当您希望重用循环内部的结果时,才需要该语法( AT&Tksh和特定语法)。zshbash

答案4

我会这样做 - 输入时间戳列表:

#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;

while ( my $ts = <DATA> ) { 
   chomp ( $ts );
   my $t = Time::Piece->new();
   print $t->epoch, " ", $t,"\n";
}

__DATA__
1442039711  
1442134211  
1442212521

这输出:

1442039711 Sat Sep 12 07:35:11 2015
1442134211 Sun Sep 13 09:50:11 2015
1442212521 Mon Sep 14 07:35:21 2015

如果您想要特定的输出格式,您可以使用strftime例如:

print $t->epoch, " ", $t->strftime("%Y-%m-%d %H:%M:%S"),"\n";

将其变成管道中的一个内衬:

 perl -MTime::Piece -nle '$t=Time::Piece->new($_); print $t->epoch, "  ", $t, "\n";'

但我可能建议改为使用该File::Find模块并在 perl 中完成整个操作。如果您在剪切之前给出目录结构的示例,我会给您一个示例。但它会是这样的:

#!/usr/bin/env perl

use strict;
use warnings;
use Time::Piece;
use File::Find; 

sub print_timestamp_if_dir {
   #skip if 'current' item is not a directory. 
   next unless -d; 
   #extract timestamp (replicating your cut command - I think?)
   my ( $timestamp ) = m/.{3}(\d{9})/; #like cut -c 3-12;

   #parse date
   my $t = Time::Piece->new($timestamp);
   #print file full path, epoch time and formatted time; 
   print $File::Find::name, " ", $t->epoch, " ", $t->strftime("%Y-%m-%d %H:%M:%S"),"\n";
}

find ( \&print_timestamp_if_dir, "." ); 

相关内容