原始文件
claudio
antonio
claudio
michele
Run Code Online (Sandbox Code Playgroud)
我只想用“克劳迪娅”更改“克劳迪奥”的第一次出现,以便我得到以下内容:
claudia
antonio
claudio
michele
Run Code Online (Sandbox Code Playgroud)
我尝试了以下方法:
sed -e '1,/claudio/s/claudio/claudia/' nomi
Run Code Online (Sandbox Code Playgroud)
上面的命令执行全局替换(它替换所有出现的 'claudio')。为什么?
Joh*_*024 36
如果您使用的是 GNU sed
,请尝试:
sed -e '0,/claudio/ s/claudio/claudia/' nomi
Run Code Online (Sandbox Code Playgroud)
sed
直到在开始该范围的行之后才开始检查结束范围的正则表达式。
来自man sed
(POSIX 联机帮助页,重点是我的):
具有两个地址的编辑命令应选择从与第一个地址匹配的第一个模式空间到与第二个地址匹配的下一个模式空间的包含范围。
虽然0
地址不是标准的,但这是sed
任何其他sed
实现都不支持的 GNU扩展。
awk
awk
工作范围更符合您的预期:
$ awk 'NR==1,/claudio/{sub(/claudio/, "claudia")} 1' nomi
claudia
antonio
claudio
michele
Run Code Online (Sandbox Code Playgroud)
解释:
NR==1,/claudio/
这是一个从第 1 行开始并以 的第一次出现结束的范围claudio
。
sub(/claudio/, "claudia")
当我们在范围内时,执行此替代命令。
1
这是 awk 用于打印该行的神秘简写。
小智 7
GNU 语法:
sed '/claudio/{s//claudia/;:p;n;bp}' file
Run Code Online (Sandbox Code Playgroud)
或者甚至(仅使用一次要替换的单词:
sed '/\(claudi\)o/{s//\1a/;:p;n;bp}' file
Run Code Online (Sandbox Code Playgroud)
或者,用 POSIX 语法:
sed -e '/claudio/{s//claudia/;:p' -e 'n;bp' -e '}' file
Run Code Online (Sandbox Code Playgroud)
works on any sed, process only as many lines as needed to find the first claudio
, works even if claudio
is in the first line and is shorter as it use only one regex string.
To change only one line you need to select only one line.
Using a 1,/claudio/
(from your question) selects:
claudio
.$ cat file
claudio 1
antonio 2
claudio 3
michele 4
$ sed -n '1,/claudio/{p}' file
claudio 1
antonio 2
claudio 3
Run Code Online (Sandbox Code Playgroud)
To select any line that contains claudio
, use:
$ sed -n `/claudio/{p}` file
claudio 1
claudio 3
Run Code Online (Sandbox Code Playgroud)
And to select only the first claudio
in the file, use:
sed -n '/claudio/{p;q}' file
claudio 1
Run Code Online (Sandbox Code Playgroud)
Then, you can make a substitution on that line only:
sed '/claudio/{s/claudio/claudia/;q}' file
claudia 1
Run Code Online (Sandbox Code Playgroud)
Which will change only the first occurrence of the regex match on the line, even if there may be more than one, on the first line that match the regex.
Of course, the /claudio/
regex could be simplified to:
$ sed '/claudio/{s//claudia/;q}' file
claudia 1
Run Code Online (Sandbox Code Playgroud)
And, then, the only thing missing is to print all other lines un-modified:
sed '/claudio/{s//claudia/;:p;n;bp}' file
Run Code Online (Sandbox Code Playgroud)
新版本的 GNUsed
支持该-z
选项。
通常,sed 通过读取一串字符直到行尾字符(换行或回车)来读取一行。
sed 的 GNU 版本在 4.2.2 版中添加了一个功能来使用“NULL”字符来代替。如果您有使用 NULL 作为记录分隔符的文件,这会很有用。某些 GNU 实用程序可以生成使用 NULL 代替新行的输出,例如“find . -print0”或“grep -lZ”。
当您想sed
在不同的行上工作时,您可以使用此选项。
echo 'claudio
antonio
claudio
michele' | sed -z 's/claudio/claudia/'
Run Code Online (Sandbox Code Playgroud)
返回
claudia
antonio
claudio
michele
Run Code Online (Sandbox Code Playgroud)
以下是 sed 的另外两个程序化工作:它们都将整个文件读入一个字符串,然后搜索将只替换第一个。
sed -n ':a;N;$bb;ba;:b;s/\(claudi\)o/\1a/;p' file
sed -n '1h;1!H;${g;s/\(claudi\)o/\1a/;p;}' file
Run Code Online (Sandbox Code Playgroud)
附评论:
sed -n ' # don't implicitly print input
:a # label "a"
N # append next line to pattern space
$bb # at the last line, goto "b"
ba # goto "a"
:b # label "b"
s/\(claudi\)o/\1a/ # replace
p # and print
' file
Run Code Online (Sandbox Code Playgroud)
sed -n ' # don't implicitly print input
1h # put line 1 in the hold space
1!H # for subsequent lines, append to hold space
${ # on the last line
g # put the hold space in pattern space
s/\(claudi\)o/\1a/ # replace
p # print
}
' file
Run Code Online (Sandbox Code Playgroud)