タブをフィールド区切りとして awk 内でソートする

タブをフィールド区切りとして awk 内でソートする

タブ区切りのファイルを、ヘッダーを保持したまま特定のフィールドで並べ替えたい。awkここで説明されているように使用しています。awk での sort と uniqsortしかし、フィールド区切りがタブであることを誰に伝えればよいのかわかりません。

おもちゃのデータ:

$ echo -e "head_1\thead_2\thead_3" > file.tsv
$ echo -e "aaa zzz\tc\t300" >> file.tsv
$ echo -e "bbb yyy ooo\ta\t100" >> file.tsv
$ echo -e "ccc xxx nnn\tb\t200" >> file.tsv
$ column -ts $'\t' file.tsv
head_1       head_2  head_3
aaa zzz      c       300
bbb yyy ooo  a       100
ccc xxx nnn  b       200

$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2" }' file.tsv | column -ts $'\t' 
head_1       head_2  head_3
ccc xxx nnn  b       200           ## note these data are sorted 
bbb yyy ooo  a       100           ## based on the xxx/yyy/zzz 
aaa zzz      c       300           ## not the a/b/c

sortフィールド区切り文字がタブであることを明示的に伝えようとすると、引用符の問題に関連していると思われる次のエラーが発生します。

$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t $'\t'" }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1  head_2  head_3

sort`awk 内の列区切り文字を指定するにはどうすればよいですか? ありがとうございます

SE の Web インターフェイスは、Notepad++ よりも構文の強調表示が優れています。私が試したことをいくつか紹介します。

$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t $'$'\t''" }' file.tsv | column -ts $'\t'
head_1       head_2  head_3
aaa zzz      c       300
bbb yyy ooo  a       100
ccc xxx nnn  b       200


$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t $'\t'" }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1  head_2  head_3

$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t "'$'\t''"" }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1  head_2  head_3

$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t "'$'\t'' }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1  head_2  head_3

答え1

次のいずれかのオプションを選択してください:

... | "sort -k2 -t \\\t "
... | "sort -k2 -t \"\t\" "
... | "sort -k2 -t'\''\t'\'' "
... | "sort -k2 -t \047\011\047" ## preferred 

\011オクテットASCIIコードですタブ文字/\047シングルクォート '

awk -v q="'" ... { print | "sort -k2 -t " q "\t" q }'
awk -v tb="'\t'" ... { print | "sort -k2 -t " tb }'
awk -v tb=$'\t' ... { print | "sort -k2 -t \"" tb "\"" }'
awk -v tb=$'\t' -v q="'" ... { print | "sort -k2 -t " q tb q }'

その他多数…; 読むawk におけるシェルの引用の問題; 参照awk のエスケープ シーケンス

答え2

これは適切なワンライナーの方法ではないかもしれませんが、シンプルでタブ文字を操作する必要がありません... :D

var=$(head -1 file.tsv);perl -ne '{ print $_ if $. > 1; }'  file.csv| sort -k2 | sed "1 i $var" | column -ts "\t"

答え3

ちなみに、データを並べ替えながら上部のヘッダーを保持するという実際の問題を解決する方法は次のとおりです。

awk -v OFS='\t' '{print (NR>1), $0}' file.tsv | sort -t$'\t' -k1,1n -k3 | cut -f2-

上記は、入力データの先頭に 0 または 1 (最初の行の場合は 0、他のすべての行の場合は 1) を追加することで機能するため、最初にそのインジケーターで並べ替えてから、実際に必要なキーで並べ替え、最後に追加されたフィールドを再度削除することができます。

段階的に動作しています:

$ awk -v OFS='\t' '{print (NR>1), $0}' file.tsv
0   head_1  head_2  head_3
1   aaa zzz c   300
1   bbb yyy ooo a   100
1   ccc xxx nnn b   200

$ awk -v OFS='\t' '{print (NR>1), $0}' file.tsv | sort -t$'\t' -k1,1n -k3
0   head_1  head_2  head_3
1   bbb yyy ooo a   100
1   ccc xxx nnn b   200
1   aaa zzz c   300

$ awk -v OFS='\t' '{print (NR>1), $0}' file.tsv | sort -t$'\t' -k1,1n -k3 | cut -f2-
head_1  head_2  head_3
bbb yyy ooo a   100
ccc xxx nnn b   200
aaa zzz c   300

関連情報