grep 管道插入 sed,替换内联;但我希望 sed 打印文件名并更改行。是否可以?

grep 管道插入 sed,替换内联;但我希望 sed 打印文件名并更改行。是否可以?

这是我的命令(故意中断):

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

如果我省略-land 管道,我会从以下位置得到这个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

相关内容