使用分隔符三重管道符号“|||”逐行合并两个文件

Fro*_*own 14 sed awk text-processing

我有两个并行文件,两种语言的行数相同,并计划用分隔符逐行合并这两个文件|||。例如,这两个文件如下:

文件A:

1Mo 1,1 I love you.
1Mo 1,2 I like you.
Hi 1,3 I am hungry.
Hi 1,4 I am foolish.
Run Code Online (Sandbox Code Playgroud)

文件乙:

1Mo 1,1 Ich liebe dich.
1Mo 1,2 Ich mag dich.
Hi 1,3 Ich habe Durst.
Hi 1,4 Ich bin neu.
Run Code Online (Sandbox Code Playgroud)

预期的输出是这样的:

1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. ||| Hi 1,4 Ich bin neu.
Run Code Online (Sandbox Code Playgroud)

我尝试了以下paste命令:

paste -d "|||" fileA fileB
Run Code Online (Sandbox Code Playgroud)

但是返回的输出只包含一个管道,例如:

1Mo 1,1 I love you. |1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. |1Mo 1,2 Ich mag dich.
Run Code Online (Sandbox Code Playgroud)

有没有办法用牛肚管分隔每对线|||

cuo*_*glm 20

使用POSIX 粘贴

:|paste -d ' ||| ' fileA - - - - fileB
Run Code Online (Sandbox Code Playgroud)

paste将连接所有输入文件的相应行。这里我们有六个文件、fileA四个来自标准 in 的虚拟文件-fileB.

分隔符列表包括一个空格、三个管道和一个空格,该顺序将被paste循环使用。

对于六个文件的第一行,fileA将与第一个虚拟文件连接(这没什么,感谢no-op :运算符),产生line1-fileA<space>.

第一个虚拟文件将通过管道与第二个虚拟文件 generate 连接line1-fileA |,然后第二个虚拟文件与第三个虚拟文件 generate line1-fileA ||,第三个虚拟文件与第四个虚拟文件 generate line1-fileA |||

和第四个虚拟文件fileB,产生line1-fileA ||| line1-fileB.

这些步骤将对所有行重复,给你预期的结果。


使用的:|是少打字,并且主要集中在交互shell使用。在脚本中,您应该使用:

</dev/null paste -d ' ||| ' fileA - - - - fileB
Run Code Online (Sandbox Code Playgroud)

以防止生成子shell。

  • ...和 ​​+1 用于智能使用来自标准输入的 4 个虚拟文件和`- - - -`,但下次你甚至可以写几行来解​​释:) (4认同)

use*_*445 7

嗯,这不使用 sed、awk 或 grep,但您可以在 bash 中轻松完成。命令是:

(while IFS= read -r a <&3 && IFS= read -r b <&4; do echo "$a ||| $b"; done) 3<fileA 4<fileB
Run Code Online (Sandbox Code Playgroud)

粘贴的问题在于分隔符是单个字符。您还可以插入单个字符并使用 sed 对其进行转换,但如果该字符已出现在输入文件中,那将有点容易出错。

  • 如果行包含任何反斜杠字符或以破折号开头,您的解决方案将不起作用。您想在每次“读​​取”之前使用“IFS=”。您可以使用“粘贴”轻松完成。请参阅 [我的回答](http://unix.stackexchange.com/a/244890/38906) 以及 [这个](http://unix.stackexchange.com/q/169716/38906) 以了解为什么要避免在 shell 脚本中使用 `while` 循环。 (2认同)

Has*_*tur 5

awk (GNU) 版本

awk '{printf ("%s ||| ", $0); getline < "fileB"; print $0 }' fileA
Run Code Online (Sandbox Code Playgroud)

使用getlinein 中的命令,如果您从指定文件设置下一个,则可以从下一个输入记录awk设置$0(列的所有变量)。getline < "filename"$0

getline < "file" 从文件的下一条记录开始设置 $0; 设置 NF。


为什么您的尝试没有按预期进行?从man paste我们可以阅读

-d, --delimiters=LIST
     reuse characters from LIST instead of TABs
Run Code Online (Sandbox Code Playgroud)

它为每一列使用一个分隔符

所以命令
paste -d '|*|*' fileA fileB fileA fileB给了我行

Hi 1,3 I am hungry.|Hi 1,3 Ich habe Durst.*Hi 1,3 I am hungry.|Hi 1,3 Ich...
Hi 1,4 I am foolish.|Hi 1,4 Ich bin neu.*Hi 1,4 I am foolish.|Hi 1,4 Ich...


一个sed解决方案,我建议,以避免哪怕接近原来的尝试,因为它的补丁所获得的行为,你的初衷:

 paste -d '|' fileA fileB | sed 's/|/|||/g'
Run Code Online (Sandbox Code Playgroud)

为了避免因为您|用新的模式替换每个模式|||但您必须假设管道符号 ( |) 不存在于您的数据中,否则您必须处理特殊情况并制作更复杂的代码以避免副作用。


具有Here String [ 1 ] 构造的变体<<<

 paste -d ' ||| ' fileA - - - - fileB  <<< ''
Run Code Online (Sandbox Code Playgroud)

您使用-d ' ||| '(space,|,|,|,space) 和 4 个虚拟文件 ( - - - -)设置了 5 个分隔符,它们将从空字符串中获取数据''


在 GNU Awk 4.0.1 上测试,粘贴 (GNU coreutils) 8.21 和 sed (GNU sed) 4.2.2