Simple bash + sed s命令,用于合并六行。

huangapple go评论58阅读模式
英文:

Simple bash + sed s command to join six lines

问题

Given the following file:

temp.txt

line1
line2
line3
line4
line5
line6
line7

And the following bash/sed commands:

for (( i=0; i<6; i++ ))
do
sed "N;1s/\(.*\)\n\(.*\)/ /" temp.txt
done

doesn't produce the desired output:

line1 line2 line3 line4 line5 line6
line7

Thanks in advance for any insight you can provide.

英文:

Given the following file:

temp.txt

line1
line2
line3
line4
line5
line6
line7

And the following bash/sed commands:

for (( i=0; i&lt;6; i++ ))
do
sed &quot;N;1s/\\(.\*\\)\n\\(.\*\\)/ /&quot; temp.txt
done

doesn't produce the desired stout:

line1 line2 line3 line4 line5 line6
line7

Thanks in advance for any insight you can provide.

答案1

得分: 2

Your code is:

for ((i=0; i<6; i++))
do
sed "N;1s/\(.*\)\n\(.*\)/ /"
done
  • N 告诉 sed 读取下一行。这样做会增加当前行号。因此,测试第 1 行永远不会成功。 (您应该测试第 2 行。)
  • 您没有使用 -i,所以文件不会被更改。
  • 每次调用 sed 而不是在单个调用中执行所有操作相对低效。 (而且您只需要调用它 5 次以连接 6 行。)

一个更简单的替代方案是:

sed -i '1{N;N;N;N;N;s/\n/ /g;}' temp.txt

如果输入行数少于 6 行且最多应连接 6 行,替代脚本如下:

sed -i ':a;$q;N;1,6s/\n/ /;ta' temp.txt

请注意,BSD 风格的 sed 在标签后需要一个字面换行符。

当没有下一行时,N 的行为因实现而异。有些输出模式空间的现有内容,而其他的则遵循 posix 并将其丢弃。 (GNU sed 可以同时执行两种操作: seq 3 | sed Nseq 3 | sed --posix N.) 在标签之前加上 $q 可以避免这种不确定性并强制输出。

英文:

Your code is:

for (( i=0; i&lt;6; i++ ))
do
sed &quot;N;1s/\(.*\)\n\(.*\)/ /&quot; temp.txt
done
  • N tells sed to read the next line. By doing so the current line number is incremented. So testing for line 1 can never succeed. (You should test for line 2.)
  • You have not used -i and so the file will not be changed.
  • It is rather inefficient to call sed 6 times instead of just doing everything in a single invocation. (And you should only call it 5 times to join 6 lines.)

A simpler alternative:

sed -i &#39;1{N;N;N;N;N;s/\n/ /g;}&#39; temp.txt

In the case that the input could have fewer than 6 lines and up to 6 lines should be joined, an alternative script is:

sed -i &#39;:a;$q;N;1,6s/\n/ /;ta&#39; temp.txt

Note that BSD-ish sed requires a literal newline after any label.

Behaviour of N when there is no next line varies between implementations. Some output the existing contents of the pattern space, others follow posix and discard it. (GNU sed will do either: seq 3 | sed N vs seq 3 | sed --posix N.) Prefixing $q sidesteps this ambiguity and forces output.

答案2

得分: 1

One way:

$ sed -n -e '1h; 2,6H; 6{g; s/\n/ /g}; 6,$p' temp.txt
line1 line2 line3 line4 line5 line6
line7

The first 6 lines get added to the hold space, then on the 6th line, the hold space is moved into the pattern space, and newlines are replaced with spaces. The 6th and following lines are printed out (The -n option turns off printing by default).

(Might be GNU sed specific because of the \n in the regular expression, but since this is tagged Linux I assume that's the version you're using)


You can also use ed instead, which has an actual join command:

$ printf '%s\n' '1,5s/$/ /' 1,6j ,p Q | ed -s temp.txt
line1 line2 line3 line4 line5 line6
line7

Add a space to the end of the first 5 lines, join the first 6 lines, and print out the changed file. If you wanted to modify the file directly, just change ,p Q to w to write it out to disk.

英文:

One way:

$ sed -n -e &#39;1h; 2,6H; 6{g; s/\n/ /g}; 6,$p&#39; temp.txt
line1 line2 line3 line4 line5 line6
line7

The first 6 lines get added to the hold space, then on the 6th line, the hold space is moved into the pattern space, and newlines are replaced with spaces. The 6th and following lines are printed out (The -n option turns off printing by default).

(Might be GNU sed specific because of the \n in the regular expression, but since this is tagged linux I assume that's the version you're using)


You can also use ed instead, which has an actual join command:

$&#160;printf &#39;%s\n&#39; &#39;1,5s/$/ /&#39; 1,6j ,p Q | ed -s temp.txt                         
line1 line2 line3 line4 line5 line6
line7

Add a space to the end of the first 5 lines, join the first 6 lines, and print out the changed file. If you wanted to modify the file directly, just change ,p Q to w to write it out to disk.

答案3

得分: 1

$ awk -v max=6 '{printf("%s%s", $0, (NR<max ? " " : "\n"))}' file
line1 line2 line3 line4 line5 line6
line7

英文:
$ awk -v max=6 &#39;{printf(&quot;%s%s&quot;, $0, (NR&lt;max ? &quot; &quot; : &quot;\n&quot;))}&#39; file
line1 line2 line3 line4 line5 line6
line7

答案4

得分: 0

这可能适用于您(GNU sed):

sed ':a;N;s/\n/&amp;/5;Ta;s// /g' file

或者,如果您更喜欢:

sed ':a;N;s/[^\n]*/&amp;/6;Ta;s/\n/ /g' file

或者使用paste:

paste -sd' \n' file

英文:

This might work for you (GNU sed):

sed &#39;:a;N;s/\n/&amp;/5;Ta;s// /g&#39; file

Or if you prefer:

sed &#39;:a;N;s/[^\n]*/&amp;/6;Ta;s/\n/ /g&#39; file

Or with paste:

paste -sd&#39;     \n&#39; file

答案5

得分: 0

line1 line2 line3 line4 line5 line6
line7
另一种稍微更高效的方法(*124个微操作而不是153个*):

gawk 'ORS < FS ? ORS = FS : NR % 6 || ORS = RS' ORS=' '
英文:
echo &#39;
line1
line2
line3
line4
line5
line6
line7&#39; | 

 mawk &#39;!__ &lt; (_ = NR % 6) || ORS = _ ? OFS : RS&#39; ORS=&#39; &#39;    

line1 line2 line3 line4 line5 line6
line7  

another way to be a tiny bit more efficient (124 micro-ops instead of 153) :


gawk &#39;ORS &lt; FS ? ORS = FS : NR % 6 || ORS = RS&#39; ORS=&#39; &#39; 

huangapple
  • 本文由 发表于 2023年7月3日 09:50:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76601447.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定