【问题标题】:How to fill empty lines from one file with corresponding lines from another file, in BASH?如何在 BASH 中用另一个文件中的相应行填充一个文件中的空行?
【发布时间】:2014-03-01 05:04:17
【问题描述】:

我有两个文件,file1.txtfile2.txt。每个都有相同数量的行,但file1.txt 中的某些行是空的。这在两个文件的内容并行显示时最容易看到:

file1.txt     file2.txt
cat           bear
fish          eagle
spider        leopard
              snail
catfish       rainbow trout
              snake
              koala
rabbit        fish

我需要将这些文件组合在一起,以便file1.txt 中的空行填充来自file2.txt 的行(具有相同行号)中的数据。 file3.txt 中的结果如下所示:

cat
fish
spider
snail
catfish
snake
koala
rabbit

到目前为止,我能做的最好的事情是创建一个 while read -r line 循环,创建一个计数器来计算 while 循环的循环次数,然后使用 if 条件检查 $line 是否为空,然后使用cut根据计数器上的数字从file2.txt获取行号。这种方法似乎效率很低。

  • 有时file2.txt 可能包含一些空行。如果file1.txt 有一个空行并且file2.txt 在同一位置也有一个空行,则结果是file3.txt 中的一个空行。

如何用另一个文件中的对应行填充一个文件中的空行?

【问题讨论】:

    标签: bash awk cut


    【解决方案1】:
    paste file1.txt file2.txt | awk -F '\t' '$1 { print $1 ; next } { print $2 }'
    

    【讨论】:

    • 不错。我不知道paste :)
    • 如果file1 中带有标签的值,这将失败,例如more catfish,它只会打印more(标签前的第一个单词),请参阅@Homayoun Afshari 发布的解决方法paste -d"#" 但如果数据包含 # 也会失败
    【解决方案2】:

    这里是用awk处理这些文件的方法:

    awk 'FNR==NR {a[NR]=$0;next} {print (NF?$0:a[FNR])}' file2 file1
    cat
    fish
    spider
    snail
    catfish
    snake
    koala
    rabbit
    

    首先它将file2的所有数据存储在数组a中,使用记录号作为索引
    然后它会打印file1,如果file1 包含每条记录的数据
    如果这条记录有数据,则使用它,如果没有,则从file2获取一个

    【讨论】:

    • +1:可以缩短为awk 'FNR==NR{a[NR]=$0;next}{$0=$0?$0:a[FNR]}1' file2 file1
    • 如果 file1 中的行填充了任何计算结果为零的内容(例如 0 或 0.0 或 ...),则该操作将失败。您还需要将三元表达式括起来以实现可移植性。将其更改为awk 'FNR==NR {a[NR]=$0;next} {print (NF?$0:a[FNR])}' file2 file1
    • 添加了括号。我确实需要记住便携性:)
    • 关于测试NF 而不是$0 以查看一行是否为空的评论的第一部分实际上是恕我直言更重要的部分。或者你可以测试$0 == "",如果你想将空格字符的行与完全空的行区别对待。
    【解决方案3】:

    一个带有 getline 的(在这种情况下是无害的):

    awk '{getline p<f; print NF?$0:p; p=x}' f=file2 file1
    

    【讨论】:

      【解决方案4】:

      只是为了好玩:

      paste file1.txt file2.txt | sed -E 's/^   //g' | cut -f1
      

      这会删除行首的制表符(file1 中缺少的制表符),然后取第一列。

      (对于 OSX,\t 在 sed 中不起作用,因此要获取 TAB 字符,请输入 ctrl-V 然后 Tab)

      【讨论】:

        【解决方案5】:

        没有 awk 的解决方案:

        paste -d"#" file1 file2 | sed 's/^#\(.*\)/\1/' | cut -d"#" -f1
        

        【讨论】:

          【解决方案6】:

          这是一个仅限 Bash 的解决方案。

          for i in 1 2; do
              while read line; do
                  if [ $i -eq 1 ]; then
                      arr1+=("$line")
                  else
                      arr2+=("$line")
                  fi
              done < file${i}.txt
          done
          for r in ${!arr1[@]}; do
              if [[ -n ${arr1[$r]} ]]; then
                      echo ${arr1[$r]}
              else
                      echo ${arr2[$r]}
              fi
          done > file3.txt
          

          【讨论】:

            猜你喜欢
            • 2020-06-23
            • 2019-07-26
            • 2020-10-12
            • 1970-01-01
            • 2016-11-20
            • 2017-01-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多