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。
嗯,这不使用 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 对其进行转换,但如果该字符已出现在输入文件中,那将有点容易出错。
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