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

Bla*_*aMa 14 shell find date

我有名称为时间戳的目录,自 1970-01-01 以来以毫秒为单位:

1439715011728
1439793321429
1439879712214
.
.
Run Code Online (Sandbox Code Playgroud)

我需要一个输出,如:

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
.
.
Run Code Online (Sandbox Code Playgroud)

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

find ./ -type d | cut -c 3-12
Run Code Online (Sandbox Code Playgroud)

但是我不能将输出放到下一个命令:date -d @xxxxxx并操作输出。

我怎样才能做到这一点?

Ant*_*hon 10

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

find * -type d | cut -c 1-10 | parallel date --date=@{} +%c
Run Code Online (Sandbox Code Playgroud)

要得到

Sat 12 Sep 2015 08:35:11 CEST
Sun 13 Sep 2015 10:50:11 CEST
Mon 14 Sep 2015 08:35:21 CEST
Run Code Online (Sandbox Code Playgroud)

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

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

或者:

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

要得到:

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
Run Code Online (Sandbox Code Playgroud)

然而,这样做更简单³:

find * -type d -printf "@%.10f\n" | date -f - +'%s  %c'
Run Code Online (Sandbox Code Playgroud)

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

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

find ./ -mindepth 1 -type d -printf "@%.10f\n" | date -f - +'%s  %c'
Run Code Online (Sandbox Code Playgroud)

sort在需要时插入:

find ./ -mindepth 1 -type d -printf "@%.10f\n" | sort | date -f - +'%s  %c'
Run Code Online (Sandbox Code Playgroud)

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

  • 它确实:`find ./ -type d | 切-c 3-12 | xargs -I{} 日期 --d @{} +'%Y-%m-%d'` (4认同)

Sté*_*las 10

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

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

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


Wou*_*lst 8

你已经有了:

find ./ -type d | cut -c 3-12
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

将 放在find子shell 中,并将while 循环保留在主shell 中。但是ksh,仅当您希望重用循环内部的结果时才需要该语法(AT&Tzshbash特定的)。


Gil*_*il' 6

如果您有 GNU 日期,它可以转换从输入文件中读取的日期。您只需要稍微按摩时间戳,以便它可以识别它们。基于 Unix 纪元的时间戳的输入语法@后跟秒数,其中可以包含小数点。

find ./ -type d ! -name '*[!0-9]*' |
sed -e 's~.*/~@~' -e 's~[0-9][0-9][0-9]$~.&~' |
date -f - +'%s  %c'
Run Code Online (Sandbox Code Playgroud)


Sob*_*que 5

我会做的很简单 - 输入时间戳列表:

#!/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
Run Code Online (Sandbox Code Playgroud)

这输出:

1442039711 Sat Sep 12 07:35:11 2015
1442134211 Sun Sep 13 09:50:11 2015
1442212521 Mon Sep 14 07:35:21 2015
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

但我可能会建议改为查看使用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, "." ); 
Run Code Online (Sandbox Code Playgroud)