web-dev-qa-db-ja.com

コマンド「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と出力を操作します。

これどうやってするの?

14
BlaMa

あなたは正しい軌道に乗っています(より簡単な解決策については、2つまたは3つのコマンドのみを実行します。以下を参照してください)。現在のディレクトリを削除するには、*ではなく./を使用する必要があります。これにより、ミリ秒の削減が多少簡単になり、結果をGNU parallelまたはxargs²:

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'

¹ これは、例にあるように、ネストされたサブディレクトリがないことを前提としています。 ./ -mindepth 1の代わりに*を使用することもできます
²@hobbsと@don_crisstiが示唆しているように、ここでparallelxargs -I{}に置き換えることができます。 ³datesファイル読み取り機能を使用するためのGillesの回答に基づく

10
Anthon

ループ内でファイルごとにいくつかのコマンドを実行することは避けます。あなたはすでにGNUismを使っているので:

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

2つのコマンドを実行するだけです。 strftime()は、_date -d_のようにGNU固有です。

10

あなたはすでに持っています:

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

ただし、一部のシェルでは、その構文はサブシェルでwhileループを取得します。つまり、そこに変数を設定しようとしても、ループを抜けると変数は表示されません。それを修正するには、物事を少し頭に向ける必要があります。

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

findをサブシェルに配置し、whileループをメインシェルに保持します。ただし、その構文(AT&T kshzshおよびbash固有)は、ループ内からの結果を再利用する場合にのみ必要です。

8
Wouter Verhelst

GNU日付がある場合は、入力ファイルから読み取った日付を変換できます。タイムスタンプを少しマッサージするだけで、それらを認識できます。タイムスタンプの入力構文は、 Unixエポックは@の後に秒数が続きます。小数点を含めることができます。

find ./ -type d ! -name '*[!0-9]*' |
sed -e 's~.*/~@~' -e 's~[0-9][0-9][0-9]$~.&~' |
date -f - +'%s  %c'

私はそれを徹底的に行います-タイムスタンプのリストをフィードします:

#!/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";

これをパイプの1つのライナーに変えるには:

 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, "." ); 
5
Sobrique

zshおよび strftime 組み込み:

zmodload zsh/datetime
for d (*(/))
strftime '%s %a %b %d %T %Z %Y' $d

これは、現在のディレクトリ内のすべてのディレクトリ名が実際にはエポック時間であることを前提としています。
例のそれらの数値をどのように処理するかを明確にすれば、さらにフィルタリング/処理を行うことができます(レイア姫とルークスカイウォーカーの誕生日に対応するエポック時間に似ています...)。少なくとも10桁に一致するディレクトリ名を再帰的に検索し、最初の10桁に基づいて日付を計算します。

setopt extendedglob
zmodload zsh/datetime
for d (**/[0-9](#c10,)(/))
strftime '%s %a %b %d %T %Z %Y' ${${d:t}:0:10}
2
don_crissti

GNU Parallelを使用:

find ./ -type d | cut -c 3-12 | parallel -k 'echo {} `date -d @{}`'

スペースの代わりに\ tを受け入れることができる場合:

find ./ -type d | cut -c 3-12 | parallel -k --tag date -d @{}
2
Ole Tange

Pythonを使用します(これはおそらく最も遅いソリューションです)

for i in $(ls -A); do echo $i | xargs python -c "from sys import argv;from time import strftime;from datetime import datetime;print datetime.fromtimestamp(float(argv[1][:-3])).strftime('%Y-%m-%d %H:%M:%S'),'---',argv[1]"; done

与える:

2015-08-30 08:48:59 --- 1440917339340
2015-08-31 08:00:22 --- 1441000822458
2015-09-01 08:00:32 --- 1441087232437
2015-09-01 16:48:43 --- 1441118923773
2015-09-02 08:00:11 --- 1441173611869
2015-09-03 08:00:32 --- 1441260032393
2015-09-04 08:00:21 --- 1441346421651
0
lukaz

通常、findコマンドは、exec引数を使用して任意のコマンドと連鎖させることができます。

あなたの場合、あなたはこのようにすることができます:

find . -type d | cut -c 3-12 | while read line
do
       echo -n "${line}  "
       date -d $line
done
0
SHW