用另一个文件的每一行填充文本文件中的空白行。

3

基本上我有一个带有许多空行的文本文件。我们称其为 time.txt ,该文件的一部分如下所示:

       1          5   20    
       2          5   12    
       1          6   3    
       2          6   4

       1          10   30    
       2          10   21    
       1          11   27    
       2          12   8
       1          11   34    
       2          12   20

       1          10   30    
       2          10   21  

现在,我有另一个文件,名为location.txt,其中包含与time.txt中空行数量相同的行数。它看起来像这样:

   110      -7      5.000              66
   110      -7      5.000              99
   110      -7      5.000              60

我的要求很简单:我只想用location.txt的每一行填充time.txt中的空白行,以达到预期的结果:

   110      -7      5.000              66
       1          5   20    
       2          5   12    
       1          6   3    
       2          6   4
   110      -7      5.000              99
       1          10   30    
       2          10   21    
       1          11   27    
       2          12   8
       1          11   34    
       2          12   20
   110      -7      5.000              60
       1          10   30    
       2          10   21  

我的解决方法是逐行阅读 location.txt,在循环内将每行存储到变量中,然后使用 awk 检测 time.txt 中的空行并用存储的循环变量替换。我的代码如下:

time="time.txt"
location="location.txt"
while read -r lines_locs; do
    awk '!NF{$0=$lines_locs}1' $time
done < "$location"

但是,这仅仅在我的屏幕上打印出了 time.txt,没有进行任何替换。另外,我打印的行数比预期的行数要多。我确定我忽略了某些东西,如果有人能指出来,我会很高兴的。

你期望每个文件有多少行?此外,空白行真的是空白的吗,还是它们包含空格(例如空格、制表符)? - markp-fuso
time.txt 文件中有 39757 行,在 location.txt 文件中有 643 行。 - dex10
3个回答

5

使用 getline 的 awk 中的一个示例:

$ awk -v file="$location" 'NF==0{if((getline < file)<=0)$0=""}1' "$time"

解释:

$ awk -v file="$location" '    # location file as parameter
NF==0 {                        # NF==0 considers bare space records empty
    if((getline < file)<=0)    # when empty read from another file. if failure
        $0=""                  # reset the record. see comments for discussion
}1' "$time"                    # output

输出:

   110      -7      5.000              66
       1          5   20    
       2          5   12    
       1          6   3    
       2          6   4
   110      -7      5.000              99
       1          10   30    
       2          10   21    
       1          11   27    
       2          12   8
       1          11   34    
       2          12   20
   110      -7      5.000              60
       1          10   30    
       2          10   21  

如果文件location的记录用尽,脚本将打印空记录。有关讨论,请参见注释。

1
这太快了,而且效率高,谢谢! - dex10
1
只需注意getline问题,特别是在使用其输出之前未测试其成功的情况下 - 请参见http://awk.freeshell.org/AllAboutGetline。顺便说一句,您可以通过测试`NF`而不是`$0==""`来提高效率。 - Ed Morton
1
@EdMorton 感谢您关于 NF 的提示。在 getline 问题上:您是否对此应用程序有任何特定的问题想到?我会假设在读取错误的情况下 $0 被设置为 "",并且 if((getline < file) <= 0){print "";next} 并不更安全? - James Brown
1
最明显的问题是location.txt文件中的行数不足以填补time.txt中的空白行,或者在awk执行时location.txt变得无法读取。当getline失败时,$0将保持之前调用getline时的内容(所以在这种情况下是""),防止它的方法更像是if ( (getline < file) <=0 ) print "the sky is falling" | "cat>&2"或类似的方式,这样用户就会收到有关此问题的警告。我发布的非getline版本也不会报告location.txt中是否有足够的行数 - 留作练习 :-) - Ed Morton
1
当前示例不适合演示此问题,因为它在空输入行上调用getline并在getline失败时打印空行,但是使用getline的一个常见问题是当您尝试使用命令输出更新输入文件时,其中一个输入文件(比如file1)无法打开。如果您使用awk 'script' file1 file2 > tmp && mv tmp file2,那么无法打开file1意味着我们不会覆盖另一个输入文件file2。如果我们改用awk '...getline < file...' file2 > tmp && mv tmp file2而没有保护,则file2将被覆盖。 - Ed Morton
显示剩余2条评论

3
如果您熟悉GNU sed,您可以使用它。
sed -e '/^$/{R '"$location" -e 'd}' "$time"
  • /^$/ 匹配 $time 文件中的空行
  • R 命令允许您从给定文件(在本例中为$location)逐行读取一行
  • d 命令然后删除空行
  • 如果匹配到空行,但没有更多可读取的行,则删除该空行

如果您想就地修改 $time 文件,请使用 sed -i 命令。


1
假设 location.txt 文件大小不超过内存容量:
$ awk 'NR==FNR{loc[NR]=$0; next} {print (NF ? $0 : loc[++c])}' location.txt time.txt
   110      -7      5.000              66
       1          5   20
       2          5   12
       1          6   3
       2          6   4
   110      -7      5.000              99
       1          10   30
       2          10   21
       1          11   27
       2          12   8
       1          11   34
       2          12   20
   110      -7      5.000              60
       1          10   30
       2          10   21

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接