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
ประสิทธิภาพเทียบกับโซลูชัน Perl โดย Jonathan บนไฟล์ 10,000 บรรทัด
$ 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
แก้ไขโดย Ed Morton (@ 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
ซึ่งแทบจะไม่ใช้หน่วยความจำ แต่อ่านไฟล์อินพุตหนึ่งครั้งต่อจำนวนฟิลด์ในบรรทัดดังนั้นจึงช้ากว่าเวอร์ชันที่อ่านไฟล์ทั้งหมดลงในหน่วยความจำ นอกจากนี้ยังถือว่าจำนวนของเขตจะเหมือนกันในแต่ละบรรทัดและจะใช้ GNU awk สำหรับENDFILE
และARGIND
แต่ awk ใด ๆ ที่สามารถทำเช่นเดียวกันกับการทดสอบและFNR==1
END