为什么当我将其添加到当前正在运行的 sed 时这不起作用?

为什么当我将其添加到当前正在运行的 sed 时这不起作用?

我有一个如下所示的文本文件:

(empty) 
str
int
int 

如果我将其添加s/^/\</g到我当前的 sed (使其成为's/\&/\</g;s/\</\ /g;s/^/\</g'),这就是输出。

< ##only this line gets a < 
str
int
int 

但是如果我新建一行,然后输入整个命令,例如sed -i '' 's/^/\</g' *.p*,这就是输出

< 
<str
<int
<int 

这有什么区别呢?

答案1

区别在于输入和输出。在第一种情况下,您插入了\n换行符,是的,但您仍在相同的模式空间上操作 - 因此^模式空间的头部仍保留在原处,即使它包含嵌入的换行符 - 每次出现时您都会插入换行符<

但在第二种情况下,您正在使用新的sed并读取最后一个seds 输出作为输入 - 因此,所有这些换行符现在都将第一个循环计数作为单独的输入行注入,并且每个换行符都有自己的^模式空间头。

echo ..... | 
sed 's/./&\
/g;s/^/sed1/' |
sed 's/^/sed2/'

sed2sed1.
sed2.
sed2.
sed2.
sed2.
sed2

顺便一提...

sed 's/&/</g;s/</\
/g'

...可能更容易写...

sed 'y/&</\n\n/'

...但是如果你只是想在每个后面添加一个换行符[&<]并替换每个,&那么<你可以这样做:

sed 's/[&<]/<\
/g'

...但是您的输出与您的输入根本不匹配...

答案2

sed 'expression;expression' 

是相同的

sed -e 'expression' -e 'expression'

其中,在几个简单的情况下,与

sed -e 'expression' | sed -e 'expression'

就您而言(据我所知),您正在尝试将所有内容更改&<.然后全部<换行,最后添加<到行的开头:

s/\&/\</g;s/\</\
/g;s/^/\</g

根据给定的输入,该sed脚本将使用 BSD 执行以下操作sed

$ sed -f script.sed file
<
<

<

<

或者,使用 GNU sed

$ gsed -f script.sed file
<
<
str
<
int
<
int

为什么是这样?

  1. 首先,&文件中没有(\前面的&可以另外删除),因此第一个表达式是无操作。
  2. 第二个表达式匹配\<单词边界(的开头)。老实说,我对为什么 BSD 删除该文本感到有点困惑sed(我将看看这是否是 OpenBSD 中的错误sed)。因此,这会在示例文件的每个单词的开头插入一个换行符。
  3. 第三个表达式仍然对同一(现已修改)输入行进行操作,并<在该行的开头插入 a 。

与此相反,单个表达式s/^/\</g(其中不需要\前面的<g修饰符)将仅<在每行的开头插入 a 。


后续:已确认sedOpenBSD 6.1-stable 上的实现存在一个错误,涉及在以插入的换行符开头的行前面添加字符串。补丁已提交。

相关内容