【问题标题】:How to interleave columns from two files?如何交错来自两个文件的列?
【发布时间】:2018-02-08 19:36:08
【问题描述】:

假设我们有两个文件(大小相同的 m*n 矩阵),包含列:

A1, A2, A3, A4, ..., An 

B1, B2, B3, B4, ..., Bn 

预期的输出是:

A1, B1, A2, B2, A3, B3, A4, B4, ..., An, Bn 

如何做到这一点?我猜有一些 awk 单行,但我无法构建正确的...

【问题讨论】:

  • 你试过什么?我们这里的大多数人都很乐意帮助你提高你的手艺,但作为短期无偿编程人员不太乐意。在MCVE 中向我们展示您迄今为止的工作、您期望的结果和您得到的结果,我们将帮助您解决问题。

标签: join text awk merge


【解决方案1】:
awk '
    BEGIN { FS=OFS=", " }
    NR==FNR { a[NR]=$0; next }
    {
        split(a[FNR],f)
        for (i=1;i<=NF;i++) {
            printf "%s%s%s%s", f[i], OFS, $i, (i<NF?OFS:ORS)
        }
    }
' a.txt b.txt

【讨论】:

    【解决方案2】:

    考虑到两个文件具有相同的行数和字段数 = 相同的数组维度,在我的测试中这样的事情似乎没问题:

    $ cat file1
    a1,a2,a3
    a4,a5,a6
    
    $ cat file2
    b1,b2,b3
    b4,b5,b6
    
    $ awk 'NR==FNR{f1[FNR]=$0;next};{split(f1[FNR],ff1,",");split($0,ff2,","); \
    for (f=1;f<=length(ff1);f++) printf ff1[f]","ff2[f](f!=length(ff1)?",":"\n")}' file1 file2
    a1,b1,a2,b2,a3,b3
    a4,b4,a5,b5,a6,b6
    

    快速解释:
    awk 先读取第一个文件,然后读取第二个文件。
    NR==FNR{f1[FNR]=$0;next}:读取第一个文件并创建一个数组 f1,其中包含 file1 的行号并包含整行 $0

    当第一个文件完成后,剩下的代码在文件2的处理过程中执行:

    split(f1[FNR],ff1,",") :由于两个文件的行数相同,因此这两个文件使用逗号作为分隔符将先前读取的记录从 file1(存储在数组 f1 中)拆分为新数组 ff1。

    split($0,ff2,",") :类似地,这将 $0 = 当前记录 / file2 的当前行拆分为一个名为 ff2 的数组,使用逗号作为分隔符。

    for (f=1;f&lt;=length(ff1);f++) printf ff1[f]","ff2[f](f!=length(ff1)?",":"\n")
    这个循环遍历 ff1 的数组元素(ff1 与 ff2 的长度相同)并打印来自 ff1 和 ff2 的数据。

    (f!=length(ff1)?",":"\n") :当我们还没有到达数组 ff1/ff2 的末尾时,这会打印逗号 ,,否则会打印一个换行符 \n

    【讨论】:

    • 这和 Ed Morton 的答案都可以正常工作(如问题所示,文件是 m*n 矩阵,而不仅仅是一行)。由于详细的解释,将此答案标记为正确。
    【解决方案3】:

    使用trrs (reshape a data array),如果有的话。如果没有,请与您当地的管理员交谈或入侵地球。一、测试数据:

    $ cat foo bar
    a1,a2,a3
    b1,b2,b3
    

    将其发送至tr,将, 替换为空格:

    $ cat foo bar | tr , ' '
    a1 a2 a3
    b1 b2 b3
    

    然后转到rs 进行转置:

    $ cat foo bar | tr , ' ' | rs -T
    a1  b1
    a2  b2
    a3  b3
    

    最后到另一个rs 挤上一行:

    $ cat foo bar | tr , ' ' | rs -T | rs 1
    a1  b1  a2  b2  a3  b3
    

    最后一个rs 可以替换为tr \n' ' 'rs 尊重输入和输出的分隔符​​,请参阅手册页。我故意省略了逗号。

    【讨论】:

      【解决方案4】:

      粘贴 + tr + sed Unix shell 的技巧:

      file1 内容:

      A1, A2, A3, A4, A5, A6, A7
      

      file2内容:

      B1, B2, B3, B4, B5, B6, B7
      

      paste <(tr ',' '\n' <file1) <(tr ',' '\n' <file2) | paste -s | sed 's/[[:space:]]\+/, /g'
      

      输出:

      A1, B1, A2, B2, A3, B3, A4, B4, A5, B5, A6, B6, A7, B7
      

      【讨论】:

      • 重要的是要指出此解决方案依赖于bash 进行进程替换。 OP 没有说明他们使用的是什么 shell 或操作系统。
      • @ghoti,添加 用于 Unix shell
      • 进程替换不是 ash、dash、csh、tcsh 的一部分。我相信 bash 的符号由 AT&T ksh 共享(但我认为不是 pdksh),但是这个非 POSIX 功能在 zsh 中的工作方式不同,我不知道它是否在 fish 中受支持。那么“for Unix shell”是什么意思呢?
      【解决方案5】:

      如果按照您的输入建议,您只使用每个输入的单行,那么按记录处理可能比按字段处理更容易。您可以通过标准输入读取一个文件,并显式读取另一个文件。

      作为一个班轮,这可能看起来像这样:

      awk 'BEGIN {ORS=RS=","} {print $1; getline < "f2"; print $1}' f1; echo
      

      为了便于阅读,用 cmets 拆分出来:

      awk '
        BEGIN { ORS=RS="," }     # record separator is a comma!
        {
          print $1               # print a trimmed (1-field) record from the first file,
          getline < "file2"      # then get the next record from the second file.
          print $1               # print a record from the second file.
        }
      ' file1
      echo                       # print a newline, since awk didn't.
      

      如果您希望输出在逗号后有空格,您可以将 BEGIN 块中的代码替换为:

        BEGIN {RS=","; ORS=", "}
      

      【讨论】:

        【解决方案6】:

        使用awkpaste 的另一种解决方案不会有什么坏处。

        paste -d',' file1 file2 | awk -F ',' '{ 
            z = ""
            for (i=1; i <= NF/2; ++i){ 
                x = i+(NF/2)
                y = $i","$x
                z = z","y
            }
            print substr(z,2,length(z))
        }' 
        

        首先,paste -d',' file1 file2 同一行索引下的两个文件,使用相同的字段分隔符合并它们 = ,

        然后,在awk 中,-F ',' 将逗号作为字段分隔符并循环遍历 1/2 列索引 i &lt;= NF/2,找到对应的列以交错 x = i+(NF/2) 并创建一个新的逗号分隔字符串两个值y = $i","$x。最后,将这些新字符串连接成一个空字符串z = z","y,并在循环后打印,不包括第一个逗号print substr(z,2,length(z))

        就个人而言,我发现这比以前使用awk 的一些解决方案更明确。

        【讨论】:

          猜你喜欢
          • 2011-04-30
          • 2015-09-19
          • 2021-10-01
          • 1970-01-01
          • 2017-11-12
          • 1970-01-01
          • 2016-12-21
          相关资源
          最近更新 更多