レコード内の日付/時刻位置が異なる可能性があるレコードの日付/時刻部分に基づいてリストをソートします。

レコード内の日付/時刻位置が異なる可能性があるレコードの日付/時刻部分に基づいてリストをソートします。

名前の日付/時刻部分に基づいてリストをソートしたいと思います。

ソートを使用できますか?以下の入力例のように列が異なる可能性があるため、ソート列を指定することはできません。

swid_ds_install_user_20171227172654_20425.log
package_user_20171227172949_5627.log
swid_state_definition_user_20171227162839_6515.log
swid_ds_install_user_20171227172732_23839.log
swid_appsrv_stop_user_20171227172258_27116.log
package_user_20171227172610_16198.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227233634_23845.log
package_user_20171227162858_7082.log

たとえば、フィールドの順序を変更できます。

awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}'

次に -d_ -k2,2 でソートし、元のファイル名を保持するためにフィールドの順序を逆にします。たとえば、sed を使用して残りの区切り文字を削除します。しかし、これは厄介です。

awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}' | sort -t'_' -k2,2 \
| awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}' | sed 's/^_//' \ 
| sed 's/_$//'

この問題をどのように処理しますか?

sedを使用して正規表現を介して日付/時刻部分を分離してソートし、出力を印刷するときに一致する正規表現だけでなく、完全なファイル名を回復するためにいくつかの組み込み機能を使用するつもりです。

別のレプリカを作成していないことを願っています。問題の説明を実際に要約することはできません。

答え1

awk -F_ '{print $(NF-1), $0}' | sort -k1,1 -n | cut -d' ' -f2-

これは、フィールド区切り文字としてawkwithを使用して_2番目のフィールドを最後のフィールド(日時)を行の先頭に追加し、sortそのフィールドの入力のみを数値でソートしてから、追加フィールドを削除するcutために使用されます。

サンプル出力は、サンプル入力を次の名前のファイルに保存しますfile

$ awk -F_ '{print $(NF-1), $0}' file  | sort -k1,1 -n | cut -d' ' -f2-
swid_state_definition_user_20171227162839_6515.log
package_user_20171227162858_7082.log
swid_appsrv_stop_user_20171227172258_27116.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227172610_16198.log
swid_ds_install_user_20171227172654_20425.log
swid_ds_install_user_20171227172732_23839.log
package_user_20171227172949_5627.log
package_user_20171227233634_23845.log

これは、日付/時刻が常に2番目から最後のフィールドにあると仮定します。もしそうならいいえこの場合、GNU awkを使用すると、次のパターンをキャプチャできます。そうだ日付/時刻のように行の先頭に追加します。

$ awk -F_ '{match($0,"_(20[0-9]{12})_",dt); print dt[1], $0}' file |
    sort -k1,1 -n | cut -d' ' -f2-

しかし、私はperlこのような場合に使用する方です。

GNU awkのmatch()関数は、オプションの3番目の引数、つまりキャプチャされた一致を格納するために使用される配列変数の名前を使用します。この場合、キャプチャは1つしかないため、配列の最初の要素に保存されます(例:)dt[1]。 IIRC、POSIX awkにはまだ正規表現一致をキャッチする方法はありません。

ところで、今の仮定は年>= 2000です。入力データが常にそうでない場合は、正規表現を適切に調整してください。

答え2

たとえば、ここでglobを使用できますzsh

printf '%s\n' *_user_*.log(oe:'REPLY=${REPLY##*user_}':)

ここではoe:...:、与えられた式に基づいてソート順序を定義します。ここでは、「user_」の右側にあるファイル名の部分を選択します。

最後の2つを並べ替えてください_*

printf '%s\n' *_*_*.log(oe:'REPLY=${(M)REPLY%_*_*}':)

答え3

次のように動作するようです。

$ perl -e 'sub key($) { $_[0] =~ /(\d+)_\d+\.log$/; return $1; }; 
     @lines = <>; print sort {key($a) cmp key($b)}  @lines;'  < files
swid_state_definition_user_20171227162839_6515.log
package_user_20171227162858_7082.log
swid_appsrv_stop_user_20171227172258_27116.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227172610_16198.log
swid_ds_install_user_20171227172654_20425.log
swid_ds_install_user_20171227172732_23839.log
package_user_20171227172949_5627.log
package_user_20171227233634_23845.log

このサブルーチンは、key日付/時刻が常にファイル名の最後の2番目の部分、.logその他の数値フィールドの前にあるように見えるという事実に基づいて数値文字列を選択します。次に、入力行を読み取り、出力をソートキーとしてソートしてkey()印刷します。

Perlはインラインコードブロックを使用してsort比較する値を取得し、より小さい、等しい、または大きい(文字列で比較)返すことができます。$a$bcmp

タイムスタンプの位置が実際に異なる場合は、subを変更して、文字列のどこからでも下線で区切られた14桁の文字列を選択できます。

sub key($) { $_[0] =~ /_(\d{14})_/; return $1; }

関連情報