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
wynik
$ 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
Wydajność w porównaniu z rozwiązaniem Perla autorstwa Jonathana w pliku zawierającym 10000 linii
$ 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
EDYCJA autorstwa Eda Mortona (@ ghostdog74 możesz usunąć, jeśli nie zgadzasz się).
Może ta wersja z bardziej wyraźnymi nazwami zmiennych pomoże odpowiedzieć na niektóre z poniższych pytań i ogólnie wyjaśni, co robi skrypt. Używa również tabulatorów jako separatora, o który pierwotnie prosił OP, więc obsługuje puste pola i przypadkowo poprawia nieco wyjście w tym konkretnym przypadku.
$ 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
Powyższe rozwiązania będą działać w każdym awk (oprócz oczywiście starego, zepsutego awk - tam YMMV).
Powyższe rozwiązania jednak wczytują cały plik do pamięci - jeśli pliki wejściowe są na to za duże, możesz to zrobić:
$ 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
który prawie nie zużywa pamięci, ale czyta plik wejściowy raz na liczbę pól w wierszu, więc będzie on znacznie wolniejszy niż wersja, która wczytuje cały plik do pamięci. Zakłada również, że liczba pól jest taka sama w każdym wierszu i używa GNU awk dla ENDFILE
i, ARGIND
ale każdy awk może zrobić to samo z testami na FNR==1
i END
.