为什么此命令仅适用于每隔一行?

为什么此命令仅适用于每隔一行?

当我跑步时\ls | xargs -I {} echo {} | sed 'N;s/\n/xxxxxxxxx/',我得到这个:

- Books aliasxxxxxxxxxA New Kind of Science
Computability-and-Logic.pdfxxxxxxxxxComputability-and-Logic_k2opt.pdf
Hein J. L. - Prolog Experiments in Discrete Mathematics, Logic, and Computability (2005).pdfxxxxxxxxxHein J. L. - Prolog Experiments in Discrete Mathematics, Logic, and Computability (2005)_k2opt.pdf
How Automated Recommendations Affect the Playlist Creation Behavior of Users.pdfxxxxxxxxxHow Automated Recommendations Affect the Playlist Creation Behavior of Users_k2opt.pdf
Lumanote- A Real-Time Interactive Music Composition Assistant.pdfxxxxxxxxxgeMsearch- Personalized Explorative Music Search.pdf
research_report_dc_02.pdfxxxxxxxxxresearch_report_dc_02_k2opt.pdf
thebookofshaders.pdfxxxxxxxxxthebookofshaders_k2opt.pdf

我不明白为什么输出不是这样的:

- Books aliasxxxxxxxxxA New Kind of SciencexxxxxxxxxComputability-and-Logic.pdfxxxxxxxxxComputability-and-Logic_k2opt.pdfxxxxxxxxxHein J. L. - Prolog Experiments in Discrete Mathematics, Logic, and Computability (2005).pdfxxxxxxxxxHein J. L. - Prolog Experiments in Discrete Mathematics, Logic, and Computability (2005)_k2opt.pdfxxxxxxxxxHow Automated Recommendations Affect the Playlist Creation Behavior of Users.pdfxxxxxxxxxHow Automated Recommendations Affect the Playlist Creation Behavior of Users_k2opt.pdf

答案1

$ seq 10  | sed 'N;s/\n/+/'
1+2
3+4
5+6
7+8
9+10

N在模式空间中添加下一行,然后s用 联接这两行+,然后sed打印该行,并为下一行输入重复该脚本(其中第 3 行和第 4 行用+...联接)。

你需要

$ seq 10 | sed 'N;N;N;N;N;N;N;N;N;s/\n/+/g'
1+2+3+4+5+6+7+8+9+10

或者在 sed 脚本中使用循环来连接所有行:

$ seq 10 | sed -e :1 -e '$!N;s/\n/+/;t1'
1+2+3+4+5+6+7+8+9+10

请注意,它将整个输入吸收到模式空间中,这无法很好地扩展到大文件。

要使用一个字符分隔符连接行,您可以使用paste

$ seq 10 | paste -sd + -
1+2+3+4+5+6+7+8+9+10

对于多字符分隔符而不将整个输入加载到内存中:

$ seq 10 | awk -v sep=-+- -vORS= 'NR>1 {print sep}; 1; END {if (NR) print RS}'
1-+-2-+-3-+-4-+-5-+-6-+-7-+-8-+-9-+-10

答案2

带注释的脚本sed

# Append the next line of input to the pattern space with an embedded newline
N

# Replace the embedded newline with the string xxxxxxxxx
s/\n/xxxxxxxxx/

# (implicit print, start next cycle, overwriting the pattern space with the next line)

因此,您读取一行,追加一行,替换+输出。然后你读第三行,追加第四行,然后替换+输出。

如果你想收藏全部线,您可以通过两种方式来做到这一点sed

  1. 使用显式循环: :top; N; $!btop; s/\n/xxxxxxxxx/g,即“追加下一行,如果还没有结束,则再做一次,然后替换所有换行符”。

  2. 使用保留空间:1{h;d;}; H; ${x;s/\n/xxxxxxxxx/g;p;}; d,即“将第一行复制到保留空间并从输入中丢弃,将所有其他行也附加到那里并从输入中删除它们,但是当到达最后一行时,交换保留空间,替换换行符并打印结果”。

这两种方法之间的主要区别在于,第一种方法直到最后才会退出第一个循环并在模式空间中构建字符串,而第二种方法对每一行输入都运行到最后并将结果累积在保持空间中。


另一种看待它的方式是使用awk.

你的sed代码本质上是

awk '{ line = $0; getline; print line "xxxxxxxxx" $0 }'

你想要的是

awk '{ line = (line == "" ? $0 : line "xxxxxxxxx" $0 ) } END { print line }'

这将模拟使用 中的保留空间sed

或者,

awk '{ line = $0; while (getline > 0) line = line "xxxxxxxxx" $0; print line }'

这将模拟使用 中的显式循环sed

答案3

发生这种情况是因为 sed 正在逐行处理。你必须这样循环:sed -e ':again' -e 'N;s/\n/xxxxx/' -e 'tagain',或者更简单的方法是使用tr "\n" "xxxxx"

相关内容