如何使用 awk 或 sed 将几行转置为列

how to transpose few rows to column using awk or sed

我想把一行中的一些数据放到当前列的侧列,。列的块 1 和块 2 由新行分隔。我该怎么做。

Cat filename
aaa
bbb
ccc
ddd

eee
fff
ggg
hhh


cat desiredFile
aaa eee
bbb fff
ccc ggg
ddd hhh

方法有很多种。使用 bash、粘贴和 GNU sed 的简单方法是

paste -d ' ' <(sed '/^$/Q' filename) <(sed '0,/^$/d' filename)

这里

  • sed '/^$/Q' filename 打印文件中直到第一个空行的所有行
  • sed '0,/^$/d' filename 打印第一个空行后的所有行
  • <() 是一个特定于 bash 的进程替换,它扩展为可以读取命令输出的管道名称(因此它可以用作输入文件名), 和
  • paste -d ' ' file1 file2 按照您描述的方式将两个文件粘贴在一起(由于 -d ' ' 由 space 分隔;如果没有该选项,它将使用制表符)

或者你可以使用 awk:

awk -v RS="" -F '\n' 'NF > n { n = NF } { for(i = 1; i <= NF; ++i) a[i] = a[i] OFS $i } END { for(i = 1; i <= n; ++i) print a[i] }' filename

对于空 RS,awk 在空行处将文件拆分为记录,对于 -F '\n',它在换行符处将这些记录拆分为字段,然后代码为

# remember maximum number of fields encountered
NF > n { n = NF }

# wade through the fields, assemble the output lines from them
{ for(i = 1; i <= NF; ++i) a[i] = a[i] OFS $i }

# in the end, print the assembled lines.
END { for(i = 1; i <= n; ++i) print a[i] }

awk 方法的优势在于它可以处理两段以上的行。

Ruby 对于单行代码很方便,它有一个内置的转置方法。使用与 Wintermute 类似的方法,我们有:

ruby -00 -F"\n" -ane '
    BEGIN {data=[]}
    data << $F
    END {data.transpose.each {|row| puts row.join(" ")}}
' file

我在测试文件中又添加了一段,它的输出是这样的:

aaa eee iii
bbb fff jjj
ccc ggg kkk
ddd hhh lll
$ cat tst.awk
BEGIN { numCols=1 }
!NF { numRows=0; ++numCols; next }
{ a[++numRows,numCols]=[=10=] }
END {
    for (r=1;r<=numRows;r++) {
        for (c=1;c<=numCols;c++) {
            printf "%s%s", a[r,c], (c<numCols?OFS:ORS)
        }
    }
}

$ awk -f tst.awk file
aaa eee
bbb fff
ccc ggg
ddd hhh