並べ替え|ユニック| xargs grep…行にスペースが含まれる場合
-
03-07-2019 - |
質問
コンマ区切りファイル" myfile.csv"がありますここで、5番目の列は日付/時刻スタンプです。 (mm / dd / yyyy hh:mm)。 重複した日付を含むすべての行をリストする必要があります(たくさんあります)
WinXPのcygwin経由でbashシェルを使用しています
$ cut -d, -f 5 myfile.csv | sort | uniq -d
重複した日付のリストを正しく返します
01/01/2005 00:22
01/01/2005 00:37
[snip]
02/29/2009 23:54
しかし、これをgrepにフィードしてすべての行を提供する方法はわかりません。
出力にスペースが含まれているため、明らかに xargs
をそのまま使用することはできません。 uniq -z -d
を実行できると思っていましたが、何らかの理由でこれらのフラグを組み合わせると、uniqは(明らかに)何も返されません。
だから、それが与えられた
$ cut -d, -f 5 myfile.csv | sort | uniq -d -z | xargs -0 -I {} grep '{}' myfile.csv
機能しない...どうすればいいですか?
perl
または別のスクリプト言語でこれを行うことができることは知っていますが、私の頑固な性質は、標準を使用して bash
でそれを行うことができると主張しています sort
、 uniq
、 find
、 grep
、 cut
などのコマンドラインツール
教えて、ああ、バッシュの達人。一般的なCLIツールを使用して必要な行のリストを取得するにはどうすればよいですか?
解決
- sort -k5,5はフィールドでソートを行い、カットを回避します。
- uniq -f 4は、uniqの最初の4つのフィールドを無視します;
- さらに、uniqで-Dを使用すると、繰り返されるすべての行が取得されます(vs -dは1行のみを取得します)。
- ただし、uniqはcsvではなくタブ区切りを想定しているため、tr '\ t' '、'で修正できます。
問題は、#5の後に異なるフィールドがある場合です。日付はすべて同じ長さですか? uniqに-w 16(時間を含める)または-w 10(日付のみ)を追加できる場合があります。
だから:
tr '\t' ',' < myfile.csv | sort -k5,5 | uniq -f 4 -D -w 16
他のヒント
uniq
の -z
オプションでは、入力をNULで区切る必要があります。 cut
の出力を次のようにフィルタリングできます:
tr '\n' '\000'
ゼロで区切られた行を取得します。次に、 sort
、 uniq
、および xargs
には、それを処理するオプションがあります。次のようなものを試してください:
cut -d, -f 5 myfile.csv | tr '\n' '\000' | sort -z | uniq -d -z | xargs -0 -I {} grep '{}' myfile.csv
編集:パイプ内の tr
の位置が間違っていました。
-dオプションを使用すると、xargsに各行全体を引数として使用するように指示できます。試してください:
cut -d, -f 5 myfile.csv | sort | uniq -d | xargs -d '\n' -I '{}' grep '{}' myfile.csv
sedでスペースをエスケープしてみてください:
echo 01/01/2005 00:37 | sed 's/ /\\ /g'
cut -d, -f 5 myfile.csv | sort | uniq -d | sed 's/ /\\ /g' | xargs -I '{}' grep '{}' myfile.csv
(さらに別の方法は、重複する日付行をIFS = $ '\ n'配列に読み込み、forループで繰り返し処理することです。)
これはawkの良い候補です:
BEGIN { FS="," }
{ split($5,A," "); date[A[0]] = date[A[0]] " " NR }
END { for (i in date) print i ":" date[i] }
- フィールドセパレーターを '、'(CSV)に設定します。
- スペースで5番目のフィールドを分割し、スティックの結果はAになります。
- 行番号を、その日付に対してすでに保存されているもののリストに連結します。
- 各日付の行番号を印刷します。