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
đầu ra
$ 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
Hiệu suất chống lại giải pháp Perl của Jonathan trên tệp 10000 dòng
$ 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
CHỈNH SỬA bởi Ed Morton (@ ghostdog74 vui lòng xóa nếu bạn không đồng ý).
Có thể phiên bản này với một số tên biến rõ ràng hơn sẽ giúp trả lời một số câu hỏi bên dưới và nói chung làm rõ tập lệnh đang làm gì. Nó cũng sử dụng các tab làm dấu phân cách mà OP đã yêu cầu ban đầu để nó xử lý các trường trống và nó ngẫu nhiên cải tiến đầu ra một chút cho trường hợp cụ thể này.
$ 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
Các giải pháp trên sẽ hoạt động trong bất kỳ awk nào (tất nhiên là ngoại trừ awk cũ, bị hỏng - có YMMV).
Tuy nhiên, các giải pháp trên có thể đọc toàn bộ tệp vào bộ nhớ - nếu các tệp đầu vào quá lớn thì bạn có thể thực hiện việc này:
$ 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
mà hầu như không sử dụng bộ nhớ nhưng đọc tệp đầu vào một lần cho mỗi số trường trên một dòng nên sẽ chậm hơn nhiều so với phiên bản đọc toàn bộ tệp vào bộ nhớ. Nó cũng giả định rằng số lượng trường là như nhau trên mỗi dòng và nó sử dụng GNU awk cho ENDFILE
và ARGIND
nhưng bất kỳ awk nào cũng có thể làm như vậy với các bài kiểm tra trên FNR==1
và END
.