英文:
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<6; i++ ))
do
sed "N;1s/\\(.\*\\)\n\\(.\*\\)/ /" 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 N
与 seq 3 | sed --posix N
.) 在标签之前加上 $q
可以避免这种不确定性并强制输出。
英文:
Your code is:
for (( i=0; i<6; i++ ))
do
sed "N;1s/\(.*\)\n\(.*\)/ /" 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 '1{N;N;N;N;N;s/\n/ /g;}' 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 ':a;$q;N;1,6s/\n/ /;ta' 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 '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.
答案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 '{printf("%s%s", $0, (NR<max ? " " : "\n"))}' file
line1 line2 line3 line4 line5 line6
line7
答案4
得分: 0
这可能适用于您(GNU sed):
sed ':a;N;s/\n/&/5;Ta;s// /g' file
或者,如果您更喜欢:
sed ':a;N;s/[^\n]*/&/6;Ta;s/\n/ /g' file
或者使用paste:
paste -sd' \n' file
英文:
This might work for you (GNU sed):
sed ':a;N;s/\n/&/5;Ta;s// /g' file
Or if you prefer:
sed ':a;N;s/[^\n]*/&/6;Ta;s/\n/ /g' file
Or with paste:
paste -sd' \n' file
答案5
得分: 0
line1 line2 line3 line4 line5 line6
line7
另一种稍微更高效的方法(*124个微操作而不是153个*):
gawk 'ORS < FS ? ORS = FS : NR % 6 || ORS = RS' ORS=' '
英文:
echo '
line1
line2
line3
line4
line5
line6
line7' |
mawk '!__ < (_ = NR % 6) || ORS = _ ? OFS : RS' ORS=' '
line1 line2 line3 line4 line5 line6
line7
another way to be a tiny bit more efficient (124
micro-ops instead of 153
) :
gawk 'ORS < FS ? ORS = FS : NR % 6 || ORS = RS' ORS=' '
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论