连接线,以记录数为模

Joining lines, modulo the number of records

假设我的流是 x*N 行长,其中 x 是记录数,N 是每条记录的列数,并且按列输出。例如,x=2, N=3:

1
2
Alice
Bob
London
New York

如何连接每一行,以记录数为模,返回列:

1   Alice   London
2   Bob     New York

如果我使用 paste,N -s,我得到转置输出。我可以使用 split-l 选项等于 N,然后用 paste 重新组合这些片段,但我想在流中进行,而不吐出所有临时文件在这个地方。

是否有 "easy" 解决方案(即,而不是调用类似 awk 的方法)?我在想可能有一些神奇的 join 解决方案,但我看不到它...


EDIT 另一个例子,当 x=5 和 N=3 时:

1
2
3
4
5
a
b
c
d
e
alpha
beta
gamma
delta
epsilon

预期输出:

1   a   alpha
2   b   beta
3   c   gamma
4   d   delta
5   e   epsilon

为了可靠地处理输入,您需要知道输出文件中的列数或输出文件中的行数。如果您只知道列数,则需要读取输入文件两次。

Hackish coreutils 解决方案

# If you don't know the number of output lines but the
# number of output columns in advance you can calculate it
# using wc -l 

# Split the file by the number of output lines
split -l"${olines}" file FOO # FOO is a prefix. Choose a better one
paste FOO*

AWK 解决方案

如果您事先知道输出列的数量,您可以使用这个 awk 脚本:

convert.awk:

BEGIN {
    # Split the file into one big record where fields are separated
    # by newlines
    RS=''
    FS='\n' 
}
FNR==NR {
    # We are reading the file twice (see invocation below)
    # When reading it the first time we store the number
    # of fields (lines) in the variable n because we need it
    # when processing the file.
    n=NF
}
{
    # n / c is the number of output lines
    # For every output line ...
    for(i=0;i<n/c;i++) {
        # ... print the columns belonging to it
        for(ii=1+i;ii<=NF;ii+=n/c) {
            printf "%s ", $ii
        }
        print "" # Adds a newline
    }
}

并这样称呼它:

awk -vc=3 -f convert.awk file file # Twice the same file

如果您事先知道输出行数,您可以使用以下 awk 脚本:

convert.awk:

BEGIN {
    # Split the file into one big record where fields are separated
    # by newlines
    RS=''
    FS='\n' 
}
{
    # x is the number of output lines and has been passed to the 
    # script. For each line in output
    for(i=0;i<x;i++){
        # ... print the columns belonging to it
        for(ii=i+1;ii<=NF;ii+=x){
            printf "%s ",$ii
        }   
        print "" # Adds a newline
    }   
}

并这样称呼它:

awk -vx=2 -f convert.awk file

您正在寻找 pr 到 "columnate" 的信息流:

pr -T -s$'\t' -3 <<'END_STREAM'
1
2
Alice
Bob
London
New York
END_STREAM
1       Alice   London
2       Bob     New York

pr 在 coreutils 中。

大多数系统应该包含一个名为 pr 的工具,用于 print 文件。它是 part of POSIX.1,因此几乎可以肯定它会出现在您将使用的任何系统上。

$ pr -3 -t < inp1
1                       a                       alpha
2                       b                       beta
3                       c                       gamma
4                       d                       delta
5                       e                       epsilon

或者,如果您愿意,

$ pr -3 -t -s, < inp1
1,a,alpha
2,b,beta
3,c,gamma
4,d,delta
5,e,epsilon

$ pr -3 -t -w 20 < inp1
1      a      alpha
2      b      beta
3      c      gamma
4      d      delta
5      e      epsilo

查看上面的 link 以获取标准使用信息,或查看 man pr 以获取您操作系统中的特定选项。