如何从命令行将每两行合并成一行?

我有一个以下格式的文本文件。 第一行是“KEY”,第二行是“VALUE”。

KEY 4048:1736 string 3 KEY 0:1772 string 1 KEY 4192:1349 string 1 KEY 7329:2407 string 2 KEY 0:1774 string 1 

我需要和键一样的值。 所以输出应该是这样的…

 KEY 4048:1736 string 3 KEY 0:1772 string 1 KEY 4192:1349 string 1 KEY 7329:2407 string 2 KEY 0:1774 string 1 

如果我可以使用一些分隔符如$或KEY 4048:1736string3,会更好

如何将两行合并成一行?

AWK:

 awk 'NR%2{printf "%s ",$0;next;}1' yourFile 

请注意,输出结尾处有一个空行。

SED:

 sed 'N;s/\n/ /' yourFile 

paste这个工作是好的:

 paste -d " " - - < filename 

杀死一条狗的方法比悬挂更多。 [1]

 awk '{key=$0; getline; print key ", " $0;}' 

把你喜欢的任何分隔符放在引号内。


参考文献:

  1. 最初的“皮肤猫的方法很多”,恢复到一个较旧的,也可能是起源的expression,也没有任何关系与宠物。

替代sed,awk,grep:

 xargs -n2 -d'\n' 

这是最好的,当你想要joinN行,你只需要空格分隔输出。

我原来的答案是xargs -n2 ,它在单词而不是线条上分开。 -d可以用来分割任何单个字符的input。

这里是我在bash中的解决scheme:

 while read line1; do read line2; echo "$line1, $line2"; done < data.txt 

虽然看起来以前的解决scheme是可行的,但如果在文档中出现单个exception,输出将会变成碎片。 下面有点安全。

 sed -n '/KEY/{ N s/\n/ /p }' somefile.txt 

这是awk另一种方法:

 awk 'ORS=NR%2?FS:RS' file 

 $ cat file KEY 4048:1736 string 3 KEY 0:1772 string 1 KEY 4192:1349 string 1 KEY 7329:2407 string 2 KEY 0:1774 string 1 

 $ awk 'ORS=NR%2?FS:RS' file KEY 4048:1736 string 3 KEY 0:1772 string 1 KEY 4192:1349 string 1 KEY 7329:2407 string 2 KEY 0:1774 string 1 

正如Ed Morton在评论中指出的那样,最好在安全性和可携带性方面增加支架。

 awk '{ ORS = (NR%2 ? FS : RS) } 1' file 

ORS代表输出logging分隔符。 我们在这里做的是使用存储行号的NR来testing一个条件。 如果NR的模是一个真值(> 0),那么我们将输出字段分隔符设置为FS (字段分隔符)的值,默认为空格,否则我们分配换行符的RS (logging分隔符)的值。

如果你想添加,作为分隔符,然后使用以下内容:

 awk '{ ORS = (NR%2 ? "," : RS) } 1' file 

“ex”是一个脚本行编辑器,与sed,awk,grep等在同一个家族中。我想这可能是你正在寻找的东西。 许多现代的vi克隆/后继者也有vi模式。

  ex -c "%g/KEY/j" -c "wq" data.txt 

这表示对于每一行,如果它匹配“KEY”,则执行以下行中的某个行。 在这个命令完成之后(针对所有行),发出一个wRite并且把它给你。

如果Perl是一个选项,你可以尝试:

 perl -0pe 's/(.*)\n(.*)\n/$1 $2\n/g' file.txt 

你可以像这样使用awk来结合2对线:

 awk '{ if (NR%2 != 0) line=$0; else {printf("%s %s\n", line, $0); line="";} } \ END {if (length(line)) print line;}' flle 

你也可以使用下面的vi命令:

 :%g/.*/j 
 nawk '$0 ~ /string$/ {printf "%s ",$0; getline; printf "%s\n", $0}' filename 

这读作为

 $0 ~ /string$/ ## matches any lines that end with the word string printf ## so print the first line without newline getline ## get the next line printf "%s\n" ## print the whole line and carriage return 

在我需要结合两条线(为了更容易处理)的情况下,但是允许数据超过特定的情况,我发现这是有用的

data.txt中

 string1=x string2=y string3 string4 

cat data.txt | nawk'$ 0〜/ string1 = / {printf“%s”,$ 0; 函数getline; printf“%s \ n”,$ 0; getline} {print}'> converted_data.txt

输出结果如下所示:

converted_data.txt

 string1=x string2=y string3 string4 

另一个使用vim的解决scheme(仅供参考)。

解决scheme1

在vim vim filename打开文件,然后执行命令:% normal Jj

这个命令退出容易理解:

  • %:对于所有的行,
  • 正常:执行正常命令
  • Jj:执行join命令,然后跳转到下一行

之后,保存文件并退出:wq

解决scheme2

在shell中执行命令vim -c ":% normal Jj" filename ,然后保存该文件并退出:wq

最简单的方法是:

  1. 删除偶数行并将其写入临时文件1中。
  2. 删除奇数行并将其写入临时文件2中。
  3. 将两个文件合并为一个通过使用粘贴命令与-d(意味着删除空间)

 sed '0~2d' file > 1 && sed '1~2d' file > 2 && paste -d " " 1 2 

 perl -0pE 's{^KEY.*?\K\s+(\d+)$}{ $1}msg;' data.txt > data_merged-lines.txt 

-0吞下整个文件,而不是逐行阅读;
pE用循环打包代码并打印输出,详见http://perldoc.perl.org/perlrun.html ;
^KEY在行开头匹配“KEY”,之后是任何事物( .*? )的非贪婪匹配

  1. 任何种类的一个或多个空格,包括换行符;
  2. 一个或多个数字(\d+) ,我们捕获并稍后重新插入为$1 ;

之后是$行的结尾。

\K方便地将其左侧的所有内容从replace中排除,因此{ $1}仅replace1-2个序列,请参阅http://perldoc.perl.org/perlre.html

一个更通用的解决scheme(允许连接多个后续行)作为shell脚本。 这在每个之间添加了一条线,因为我需要可见性,但是这很容易修复。 这个例子是“关键”行结束的地方:没有其他的行。

 #!/bin/bash # # join "The rest of the story" when the first line of each story # matches $PATTERN # Nice for looking for specific changes in bart output # PATTERN='*:'; LINEOUT="" while read line; do case $line in $PATTERN) echo "" echo $LINEOUT LINEOUT="$line" ;; "") LINEOUT="" echo "" ;; *) LINEOUT="$LINEOUT $line" ;; esac done 

尝试以下行:

 while read line1; do read line2; echo "$line1 $line2"; done <old.txt>new_file 

把分隔符放在中间

 "$line1 $line2"; 

例如,如果分隔符是| , 然后:

 "$line1|$line2"; 

你可以像这样使用xargs

 xargs -a file