我想匹配在一个文件中的模式和更换。
This command可与egrep的,xargs的和sed:
egrep -lRZ "hello" . | xargs -0 -l sed -i -e 's/hello/world/g'
问题是:它不会在MacOS上工作,因为的MacOS的xargs的不支持argumente -l。
xargs: illegal option -- l
usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]
[-L number] [-n number [-x]] [-P maxprocs] [-s size]
[utility [argument ...]]
这是怎么解决的在MacOS?
这样共有三种不兼容你要与BSD(MacOS的)事业运行到这里的GNU(Linux)的之间。
xargs
不接受-l
选项。但-l
相当于-L
除了-L
需要一个参数指定的最大行数每命令的调用传递,而如果未指定-l
默认为一个它。因此,你可以只是-l
取代-L1
。 -L
了解双方的GNU和xargs
的BSD版本的相同的方式,因此使用这是Linux和MacOS之间进行移植。
但是,在这种特殊情况下,还有另一种更简单的选择:sed
是完全能够在每次调用多个文件进行操作,所以没有理由将其限制在每次调用一个。这甚至会稍快一些,因为它并没有花太多的时间推出新的流程。所以见好就收-l
关闭。egrep
的BSD版本(和其他人在grep
家庭)都采用这个选项-Z
,但他们用它来指完全不同的事情。随着GNU,egrep -Z
每张照片的文件名后零字节(ASCII NULL字符)(匹配xargs -0
期望的内容)。但随着BSD,egrep -Z
相当于zgrep
- 它把它的输入文件为Zip存档和搜索他们的内容之前扩展它们。
幸运的是,这两个版本了解--null
调用零字节的分隔符,这样你就可以使用便携这两个平台上。-i<suffix>
指“在地方编辑,但进行备份,并且备份与指定的文件名后缀原来的”。而对于他们两个,如果后缀是零长度,它不保留备份。不幸的是,你指定一个零长度后缀的方式是不同的,(据我已经能够找到)不可调和不兼容。具体而言,GNU需要将直接连接到-i
后缀(例如-i.bkp
),所以只是通过本身指定-i
足以指定就地-没有备份模式。但BSD允许后缀作为一个单独的参数(如-i .bkp
)进行传递,所以如果你只是单独指定-i
,它会使用任何的一个参数是作为后缀(如sed -i -e 's/hello/world/g'
将使用“-e”作为后缀)。要指定就地 - 无需备份模式下,你需要遵循-i
有一个明确的空参数(例如sed -i '' -e 's/hello/world/g'
)。但是,如果你做到这一点与GNU的sed
,它会尝试执行空参数作为脚本,这将会失败。有了这一切,这里是你的命令的MacOS的版本:
egrep -lR --null "hello" . | xargs -0 sed -i '' -e 's/hello/world/g'
...这将在Linux上几乎工作 - 唯一的区别是,你需要删除''
参数sed
。如果你想要的东西,这就是Linux和MacOS之间完全可移植的,你需要指定备份文件的后缀(并将其直接附加到-i
选项,如-i.bkp
)。
grep的选项递归搜索文件,最好避免 - 他们只是弄乱你的grep指定参数和使你的脚本不可移植。不过已经有了非常好的工具,旨在发现一个非常明显的名称的文件。
你只是想在您的所有文件与hello
更换world
?如果是这样,这只是
find . -type f |
while IFS= read -r file; do
sed 's/hello/world/g' "$file" > "tmp$$" &&
mv "tmp$$" "$file"
done
这将在任何shell工作在任何UNIX系统中,除非你的文件名包含换行符。如果你不想改变文件的时间戳等不包含hello
一种方法是:
find . -type f -exec grep -q 'hello' {} \; -print |
while IFS= read -r file; do
sed 's/hello/world/g' "$file" > "tmp$$" &&
mv "tmp$$" "$file"
done