Shell脚本 - 读取两行文件并读取另一行文件的一行

时间:2015-06-01 19:09:48

标签: shell

说,我有两个文件。

File1包含:

line1
line2
line3
line4
line5
line6
line7
line8
line9
line10

和File2包含:

anotherline1
anotherline2
anotherline3

我想做一个while循环,以便将它输出到File3:

line1
line2
anotherline1
line3
line4
anotherline2
line5
line6
anotherline3
line7
line8
anotherline1
line9
line10
anotherline2

我在这里搜索了答案,但我无法弄清楚如何去做。 我必须说我在shell脚本中非常棒...

另外:“while循环”应该是到达file1的结尾。无论File2有多长,实际上,在我的个人场景中,File2总是比File1短。输出应该是:File1Line1,File1Line2,File2Line1,File1Line3,File1Line4,File2Line2 ......等等

任何帮助?

注意:如果之前已经回答过,那么mods请关闭这个问题。谷歌搜索几个小时后我找不到任何答案。

编辑:添加了关于何时结束循环的说明。

4 个答案:

答案 0 :(得分:3)

如果我正确地解释你的问题,你想要

  1. 逐步完成file1,然后
  2. 每两行后插入file2的“下一行”,每当内容不足时,再转回file2的顶部。
  3. 如果这是目标,你可以通过多种方式使用awk,但下面的shell片段可能会这样做。

    #!/usr/bin/env bash
    
    mapfile -t file2 < file2
    
    max=${#file2[@]}
    
    while read line; do
      ((count++))
      echo "$line"
      if [[ $((count%2)) == 0 ]]; then
        if [[ next -ge max ]]; then
          next=0
        fi
        echo "${file2[next++]}"
      fi
    done < file1
    

    这有一个缺点是将所有file2作为数组加载到内存中。如果这是一个问题因为文件太大,你可以添加一些shell glop来在循环的每个调用中找到特定的行,尽管这将是非常慢的。更好的是,更具体地定义您的问题,或考虑替代工具! : - )

    另请注意,mapfile命令是bash-4-ism,因此如果您使用的是较旧的Linux或OSX(仍然附带bash 3),则需要使用其他解决方案。 ..或升级到bash。

答案 1 :(得分:2)

我不知道在纯shell脚本中执行特定操作的便捷方法。你可能最好只写一个python / perl / etc。脚本。像这个awk脚本的东西会起作用,但它有些混乱:

awk '{
  print; getline; print; 
  if (!getline < "file2") { 
    close("file2");
    getline < "file2"
  };
  print
}' file1

print; getline; print将从file1打印下一行,然后获取该行,然后打印它。 if (!getline < "file2")尝试从file2读取下一行,如果失败,则关闭它,隐式重新打开它,并从file2读取第一行。最终print将从file2(下一个或第一个)打印该行。

答案 2 :(得分:2)

这个awk应该可以工作:

awk 'FNR==NR{a[++i]=$0; next} FNR%2{p=$0; curr=(FNR==1 || curr==i) ? 1 : curr+1; next}
    {print p ORS $0 ORS a[curr]}' file2 file1
line1
line2
anotherline1
line3
line4
anotherline2
line5
line6
anotherline3
line7
line8
anotherline1
line9
line10
anotherline2

编辑:更短awk(感谢@geirha):

awk 'FNR==NR{a[n++]=$0;next}1;!(FNR%2){print a[i++%n]}' file2 file1

答案 3 :(得分:1)

在原生shell中轻松完成 - 无需awk等外部工具。打开两个文件描述符,绑定到不同的文件,并迭代两者。

while :; do
  read -r line1 <&3 && printf '%s\n' "$line1" || break
  read -r line2 <&3 && printf '%s\n' "$line2" || break
  read -r line3 <&4 || { exec 4<file2 && read -r line3 <&4; }
  printf '%s\n' "$line3"
done 3<file1 4<file2 1>file3

在这种情况下,3是我们打开file1的文件描述符号,4是我们打开file2的文件描述符号。 1>file3,或简称为>file3,将文件描述符1(也称为stdout)的输出重新路由到输出文件。

如果您愿意,可以选择其他数字,但只保证3-9之间的范围可以在所有POSIX shell上免费使用。 (0-2是stdin,stdout和stderr; shell可以使用10以上的内容供自己使用,尽管在较新且更现代的shell中很少出现这种情况。)