awk '
{
for (i=1; i<=NF; i++) {
a[NR,i] = $i
}
}
NF>p { p = NF }
END {
for(j=1; j<=p; j++) {
str=a[1,j]
for(i=2; i<=NR; i++){
str=str" "a[i,j];
}
print str
}
}' file
出力
$ more file
0 1 2
3 4 5
6 7 8
9 10 11
$ ./shell.sh
0 3 6 9
1 4 7 10
2 5 8 11
10000行ファイルでのJonathanによるPerlソリューションに対するパフォーマンス
$ head -5 file
1 0 1 2
2 3 4 5
3 6 7 8
4 9 10 11
1 0 1 2
$ wc -l < file
10000
$ time perl test.pl file >/dev/null
real 0m0.480s
user 0m0.442s
sys 0m0.026s
$ time awk -f test.awk file >/dev/null
real 0m0.382s
user 0m0.367s
sys 0m0.011s
$ time perl test.pl file >/dev/null
real 0m0.481s
user 0m0.431s
sys 0m0.022s
$ time awk -f test.awk file >/dev/null
real 0m0.390s
user 0m0.370s
sys 0m0.010s
エドモートンによる編集(不承認の場合は@ ghostdog74を削除してください)。
たぶん、このバージョンにいくつかのより明示的な変数名を付けると、以下の質問のいくつかに答えるのに役立ち、スクリプトが何をしているのか一般的に明確になります。また、OPが最初に要求したセパレーターとしてタブを使用しているため、空のフィールドが処理され、この特定のケースでは、出力が少し誤って出力されます。
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{
for (rowNr=1;rowNr<=NF;rowNr++) {
cell[rowNr,NR] = $rowNr
}
maxRows = (NF > maxRows ? NF : maxRows)
maxCols = NR
}
END {
for (rowNr=1;rowNr<=maxRows;rowNr++) {
for (colNr=1;colNr<=maxCols;colNr++) {
printf "%s%s", cell[rowNr,colNr], (colNr < maxCols ? OFS : ORS)
}
}
}
$ awk -f tst.awk file
X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11
上記のソリューションは、どのawkでも機能します(もちろん、古い壊れたawkは除きます-YMMVがあります)。
上記の解決策は、ファイル全体をメモリに読み込みますが、入力ファイルが大きすぎる場合は、これを行うことができます。
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ printf "%s%s", (FNR>1 ? OFS : ""), $ARGIND }
ENDFILE {
print ""
if (ARGIND < NF) {
ARGV[ARGC] = FILENAME
ARGC++
}
}
$ awk -f tst.awk file
X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11
ほとんどメモリを使用しませんが、行のフィールド数ごとに1回入力ファイルを読み取るため、ファイル全体をメモリに読み取るバージョンよりもはるかに遅くなります。また、フィールドの数は、各ライン上で同じであると仮定し、それはのためのGNU AWKを使用ENDFILE
し、ARGIND
しかし、任意のawkは上のテストで同じことを行うことができますFNR==1
し、END
。