コマンド「date -d @xxxxxx」と「find ./」をチェーンする方法は?


14

1970-01-01以降のミリ秒単位で与えられるタイムスタンプの名前のディレクトリがあります:

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出力を操作します。

これどうやってするの?


2
それらのタイムスタンプはどのようにエポックに変換されますか?番号が長すぎるため...(最初の1つは-ですFri Oct 2 05:35:28 47592
Sobrique

1
@Sobriqueエポックから明らかにミリ秒。
ジル「SO-悪であるのをやめる」

回答:


10

あなたは正しい道を進んでいます(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のではなく、*
² 、置き換えることができるparallelxargs -I{}@hobbsと@don_crisstiが示唆されているように、それだけで、より詳細な、ここ。 ³ ファイル読み取り機能を使用するdateというGillesの回答に基づく


またはxargs、持っていない場合parallel、多くの人はおそらく持っていないでしょう。
ホッブズ

@hobbs私の知る限りではxargs、引数は次のようにどこに行くかを指定するオプションはありませんparallelしています{}
アントン

4
それはない:find ./ -type d | cut -c 3-12 | xargs -I{} date --d @{} +'%Y-%m-%d'
don_crissti

@Anthonは、-Iオプションを使用する場合に実行します。
ホッブズ

1
@ Anthon、GNUの長いオプションは、あいまいでない限り省略できます。 --dまたは--da、GNUの現在のバージョンでdate動作しますdateが、--dalekオプションが導入されると動作しなくなる可能性があります(Dalekカレンダーの日付の場合)。
ステファンシャゼラス

10

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

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

これは2つのコマンドを実行するだけです。strftime()のようなGNU固有のものdate -dです。


これは、ディレクトリ名のミリ秒を削減しませんが、要求された最初の10
Anthon

@Anthon、そうそう、その要件を逃しました。今は大丈夫です。
ステファンシャゼル

8

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

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あなたがが、ループ内からの結果を再利用するために探している場合は、特定のは)のみ必要です。


それにもかかわらず、bash固有であると言うのは正しくありません:)
Wouter Verhelst

実際、あなたが最初に書いたように、のdone <(find)代わりにdone < <(find)それは正しいものでしたyash<(...)プロセスの置換ではなく、プロセスのリダイレクトです)ので、私の編集はあなたが意図したシェルである可能性があるため、少し無頓着でした。
ステファンシャゼラス

6

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

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

datesファイル読み取りを使用する場合は+1 。これdate: invalid date ‘@’により、現在のディレクトリの翻訳(./)が得られます。また、ミリ秒を捨てることができるためsed、最後の3文字を削除するために2番目の編集を簡略化できます。または、そのすべてを削除して使用しますfind * -type d -printf "@%.10f" | date ...
-Anthon

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

この出力:

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

2

with 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

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 @{}

parallelはで書かれていることに注意してくださいperl。これにはオペレーターperlがいることを考えるとやり過ぎのようstrftime()です。のようにperl -MPOSIX -lpe '$_.=strftime(" %c", localtime substr $_, 2, 10)'
ステファンシャゼル

2
1.短いです。2. Perlを学ぶ必要はありません。
オレ丹下

1
27%短くなりますが、効率は数桁低くなります(テストでは約800倍遅くなります。シェル(/ bin / shではなくシェル)と各行の日付コマンドを生成する必要があると考えてください)すべてのCPUに一度に負荷がかかるため、システムにとって使いにくい。そして、あなたはまだ学ぶ必要がありますparallel。IMO parallelは、CPUを集中的に使用するタスクを並列化する優れたツールですが、この種のタスクにはあまり適していません。
ステファンシャゼル

ことを考慮する場合は特に、そこにはまだ受け入れ可能な解決策ですので、効率が問題ではない状況の多くは、ですが、それはまだパフォーマンスの問題を言及する価値があるの平行が通常で韻を踏む高性能人々の心インチ
ステファンシャゼル

0

通常、findコマンドは、exec引数を使用するコマンドとチェーン化できます。

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

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

0

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

すべてをPythonでやらないのはなぜですか?パイプを束ねるのではなく?
ソブリク

それは理にかなっています。同意する。
ルカズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.