这是我的命令(故意中断):
grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i '' '/FOO/{s/FOO/BAR/g; w /dev/stdout
}'
在高层:目录grep
中的 FOO blah
;仅将文件名(因为-l
)通过管道输入到sed
;sed
执行内联替换 ( -i ''
) 并打印仅更改的术语到/dev/stdout
。
如果我省略-l
and 管道,我会从以下位置得到这个grep
:
/Users/gjtorikian/blah/baz.cs:1:FOO
/Users/gjtorikian/blah/bar.js:1:FOO
我想要的是sed
执行内联替换,然后显示替换的文件和术语;例如:
/Users/gjtorikian/blah/baz.cs:1:BAR
/Users/gjtorikian/blah/bar.js:1:BAR
这样的事可能吗?如果重要的话,我宁愿只保留它grep
/ sed
。我必须grep
在之后再做一秒钟吗sed
?
答案1
一种可能性是将 的输出传递grep
到单独的sed
过滤器。
grep -l FOO "/Users/gjtorikian/blah/"* |
{ tee /dev/fd/3 |
xargs sed -i -e '/FOO/{' -e 's/FOO/BAR/g' -e 'w /dev/stdout'
} 3>&1 | sed 's/:FOO$/:BAR/'
当找到匹配项时,您可以sed
打印行号(使用命令)并进行进一步的后处理。=
使用 awk 可能会更清楚。
for x in "/Users/gjtorikian/blah/"*; do
awk '
sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"}
1 {print}
END {exit(!found)}
' "$x" >"$x.tmp" && mv "$x.tmp" "$x"
done
答案2
因为我的母语不是英语,所以我可能没听懂。
要“grep”目录,您需要“-r”。使用“-l”仅打印文件名,并且在第一次出现后停止 grep。
# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done
/etc/adduser.conf:/home
/etc/fstab:/home
/etc/fstab~:/home
/etc/libuser.conf:/home
/etc/mpd.conf:/home
/etc/mpd.conf~:/home
/etc/mtab:/home
/etc/netscsid.conf:/home
/etc/passwd:/home
/etc/passwd-:/home
/etc/sudoers:/home
/etc/sudoers.tmp~:/home
答案3
在当前目录中递归地将 FOO 替换为 BAR(安静模式)
grep -rl 'FOO' | xargs sed -i 's/FOO/BAR/'
答案4
一班轮
grep -n FOO * -R|awk -F\: '{ print $1 }'|sort|uniq|while read file; do sed -i 's/FOO/BAR/g' $file; done