我创建了一个非常复杂的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
上述准则是根据一份意见中的建议更新的。
最初的答案如下。即使在这种情况下有点过头了,它也表明您可以使用sed
、x0
中的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
$