如何在某个字符第一次出现后使用sed进行编辑



我创建了一个非常复杂的sed命令来删除与某些模式匹配的部分:

sed 's/...//Ig; s/...//Ig; s/...//Ig'

但我发现我犯了一个错误,我应该只在第一次出现:之后编辑该部分。如何修改这个sed命令和/或使用其他命令来实现它?

要编辑的行实际上是grep的输出,例如:

/foo/bar:foobar
/foobar/foo/bar:foo_bar

为了简单起见,我假设您希望用FOO替换第一个:之后出现的每个foo

sed 'h           # save the current line in the hold space
s/[^:]*://  # delete everything up to the marker
s/foo/FOO/g # YOUR COMPLICATED COMMAND GOES HERE
x           # swap pattern and hold space
s/:.*/:/    # delete from the first : to the end in the original line
G           # append hold space (: with whatever follows it)
s/n//' yourfile # remove the newline that comes with G

上述准则是根据一份意见中的建议更新的。

最初的答案如下。即使在这种情况下有点过头了,它也表明您可以使用sedx0中的null字符作为";标记";您通常可以假设它不在文本文件中(与使用可能已经在文件中的_xxx_相反((第二个版本替换了在:之前出现的foo,与我误读问题时一致。(

sed 'h           # save the current line in the hold space
s/:/x0:/   # mark the first : by prepending a null character
s/.*x0//   # delete everything up to the marker
x           # swap pattern and hold space
s/:.*//     # delete from the first : to the end in the original line
s/foo/FOO/g # YOUR COMPLICATED COMMAND GOES HERE
G           # append hold space (: with whatever follows it)
s/n//' yourfile # remove the newline that comes with G

awk可以在这里用作更好的替代方案:

awk 'BEGIN{FS=OFS=":"} {s=$1; $1=""; gsub(/a/, "@"); gsub(/o/, "0"); print s $0}' file

/foo/bar:f00b@r
/foobar/foo/bar:f00_b@r

在这里,我们使用:分割输入,并将:之前的第一个字段保存在变量s中。然后我们运行几个gsub函数来完成所有替换,最后我们用行的其余部分打印保存的变量。

这可能对你有用(GNU sed(:

sed 's/:/n&/;h;s/foo/FOO/g;s/bar/BAR/g;y/-/_/;H;g;s/n.*n//' file

在第一个:之前引入一个换行符。

将结果复制到保留空间(HS(。

全局替换/翻译一次或多次。

将图案空间(PS(附加到HS。

用HS更换PS。

删除换行符及其之间的所有内容。

首先将grep输出的每一行拆分为两行,并在偶数行上执行sed命令
看起来像

grep "something" list_of_file |
sed 's/:/n/' |
sed '0~2s/...//Ig; 0~2s/...//Ig; 0~2s/...//Ig' |
paste -d":" - -

对于0~2,您告诉sed仅在偶数线上操作
示例:

grep -E "root|127" /etc/{passwd,hosts} |
sed 's/:/n/' |
sed -r '0~2s/([0,o])/==1==/g' | 
paste -d":" - -

输出:

/etc/passwd:r==o====o==t:x:==0==:==0==:r==o====o==t:/r==o====o==t:/bin/bash
/etc/hosts:127.==0==.==0==.1    l==o==calh==o==st

您可以尝试Perl替代方案。这里有一个使用正向回溯的解决方案

$ cat grep_out.dat
/foo/bar:foobar
/foobar/foo/bar:foo_bar
$ perl -pe ' s/(?<=:)(foo)/U1/g ' grep_out.dat
/foo/bar:FOObar
/foobar/foo/bar:FOO_bar
$

最新更新