使用grep和sed查找和替换字符串

时间:2022-10-29 15:29:00

I am using the following to search a directory recursively for specific string and replace it with another:

我正在用下面的方法递归地搜索一个目录中的特定字符串,并用另一个字符串替换它:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g'

This works okay. The only problem is that if the string doesn't exist then sed fails because it doesn't get any arguments. This is a problem for me since i'm running this automatically with ANT and the build fails since sed fails.

这是好的。唯一的问题是,如果字符串不存在,那么sed失败,因为它没有任何参数。这对我来说是一个问题,因为我正在用ANT自动运行它,而构建失败了,因为sed失败了。

Is there a way to make it fail-proof in case the string is not found?

有没有一种方法可以使它在没有找到字符串的情况下不会出现故障?

I'm interested in a one line simple solution I can use (not necessarily with grep or sed but with common unix commands like these).

我感兴趣的是一种我可以使用的简单解决方案(不一定是针对grep或sed,而是针对这些常见的unix命令)。

7 个解决方案

#1


66  

You can use find and -exec directly into sed rather than first locating oldstr with grep. It's maybe a bit less efficient, but that might not be important. This way, the sed replacement is executed over all files listed by find, but if oldstr isn't there it obviously won't operate on it.

您可以直接使用find和-exec到sed中,而不是首先使用grep查找oldstr。这可能有点低效,但这可能并不重要。通过这种方式,对find列出的所有文件执行sed替换,但是如果oldstr不在,那么它显然不会对它进行操作。

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;

#2


9  

Your solution is ok. only try it in this way:

你的解决方案就可以了。只有这样尝试:

files=$(grep -rl oldstr path) && echo $files | xargs sed....

so execute the xargs only when grep return 0, e.g. when found the string in some files.

因此,只有当grep返回0时才执行xargs,例如在某些文件中找到该字符串时。

#3


7  

Standard xargs has no good way to do it; you're better off using find -exec as someone else suggested, or wrap the sed in a script which does nothing if there are no arguments. GNU xargs has the --no-run-if-empty option, and BSD / OS X xargs has the -L option which looks like it should do something similar.

标准的xargs没有好的方法;最好像其他人建议的那样使用find -exec,或者将sed封装在一个脚本中,如果没有参数,这个脚本什么都不做。GNU xargs有—无-运行-空选项,BSD / OS X xargs有-L选项,看起来应该做类似的事情。

#4


7  

I have taken Vlad's idea and changed it a little bit. Instead of

我接受了弗拉德的想法,并做了一些改变。而不是

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

Which yields

的收益率

sed: couldn't edit /dev/null: not a regular file

I'm doing in 3 different connections to the remote server

我正在做3个不同的连接到远程服务器

touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme

Although this is less elegant and requires 2 more connections to the server (maybe there's a way to do it all in one line) it does the job efficiently as well

尽管这是不那么优雅的,并且需要两个更多的连接到服务器(也许有一种方法可以做到这一点),它也能有效地完成工作。

#5


4  

I think that without using -exec you can simply provide /dev/null as at least one argument in case nothing is found:

我认为,如果不使用-exec,您可以提供/dev/null作为至少一个参数,以防什么都找不到:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

#6


1  

My use case was I wanted to replace foo:/Drive_Letter with foo:/bar/baz/xyz In my case I was able to do it with the following code. I was in the same directory location where there were bulk of files.

我的用例是,我想用foo:/Drive_Letter替换为foo:/bar/baz/xyz,在我的用例中,我可以用下面的代码替换它。我在同一目录位置,那里有大量的文件。

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

hope that helped.

希望帮助。

#7


-1  

If you are to replace a fixed string or some pattern, I would also like to add the bash builtin pattern string replacement variable substitution construct. Instead of describing it myself, I am quoting the section from the bash manual:

如果要替换一个固定字符串或某个模式,我还想添加bash内置模式字符串替换变量替换构造。我没有自己描述它,而是引用了bash手册中的一节:

${parameter/pattern/string}

$ {参数/模式/字符串}

The pattern is expanded to produce a pattern just as in pathname expansion. parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

模式被扩展为产生模式,就像路径名扩展一样。扩展参数,使用字符串替换模式对其值的最长匹配。如果模式以/开头,则模式的所有匹配将被字符串替换。通常只有第一场比赛被替换。如果模式以#开头,那么它必须在参数的扩展值的开始处匹配。如果模式以%开头,则必须在参数的展开值末尾匹配。如果字符串为空,则删除模式的匹配,并删除/以下模式。如果参数为@或*,则依次对每个位置参数应用替换操作,扩展为结果列表。如果参数是一个带有@或*的下标数组变量,那么替换操作将依次应用于数组的每个成员,扩展是结果列表。

#1


66  

You can use find and -exec directly into sed rather than first locating oldstr with grep. It's maybe a bit less efficient, but that might not be important. This way, the sed replacement is executed over all files listed by find, but if oldstr isn't there it obviously won't operate on it.

您可以直接使用find和-exec到sed中,而不是首先使用grep查找oldstr。这可能有点低效,但这可能并不重要。通过这种方式,对find列出的所有文件执行sed替换,但是如果oldstr不在,那么它显然不会对它进行操作。

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;

#2


9  

Your solution is ok. only try it in this way:

你的解决方案就可以了。只有这样尝试:

files=$(grep -rl oldstr path) && echo $files | xargs sed....

so execute the xargs only when grep return 0, e.g. when found the string in some files.

因此,只有当grep返回0时才执行xargs,例如在某些文件中找到该字符串时。

#3


7  

Standard xargs has no good way to do it; you're better off using find -exec as someone else suggested, or wrap the sed in a script which does nothing if there are no arguments. GNU xargs has the --no-run-if-empty option, and BSD / OS X xargs has the -L option which looks like it should do something similar.

标准的xargs没有好的方法;最好像其他人建议的那样使用find -exec,或者将sed封装在一个脚本中,如果没有参数,这个脚本什么都不做。GNU xargs有—无-运行-空选项,BSD / OS X xargs有-L选项,看起来应该做类似的事情。

#4


7  

I have taken Vlad's idea and changed it a little bit. Instead of

我接受了弗拉德的想法,并做了一些改变。而不是

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

Which yields

的收益率

sed: couldn't edit /dev/null: not a regular file

I'm doing in 3 different connections to the remote server

我正在做3个不同的连接到远程服务器

touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme

Although this is less elegant and requires 2 more connections to the server (maybe there's a way to do it all in one line) it does the job efficiently as well

尽管这是不那么优雅的,并且需要两个更多的连接到服务器(也许有一种方法可以做到这一点),它也能有效地完成工作。

#5


4  

I think that without using -exec you can simply provide /dev/null as at least one argument in case nothing is found:

我认为,如果不使用-exec,您可以提供/dev/null作为至少一个参数,以防什么都找不到:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

#6


1  

My use case was I wanted to replace foo:/Drive_Letter with foo:/bar/baz/xyz In my case I was able to do it with the following code. I was in the same directory location where there were bulk of files.

我的用例是,我想用foo:/Drive_Letter替换为foo:/bar/baz/xyz,在我的用例中,我可以用下面的代码替换它。我在同一目录位置,那里有大量的文件。

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

hope that helped.

希望帮助。

#7


-1  

If you are to replace a fixed string or some pattern, I would also like to add the bash builtin pattern string replacement variable substitution construct. Instead of describing it myself, I am quoting the section from the bash manual:

如果要替换一个固定字符串或某个模式,我还想添加bash内置模式字符串替换变量替换构造。我没有自己描述它,而是引用了bash手册中的一节:

${parameter/pattern/string}

$ {参数/模式/字符串}

The pattern is expanded to produce a pattern just as in pathname expansion. parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

模式被扩展为产生模式,就像路径名扩展一样。扩展参数,使用字符串替换模式对其值的最长匹配。如果模式以/开头,则模式的所有匹配将被字符串替换。通常只有第一场比赛被替换。如果模式以#开头,那么它必须在参数的扩展值的开始处匹配。如果模式以%开头,则必须在参数的展开值末尾匹配。如果字符串为空,则删除模式的匹配,并删除/以下模式。如果参数为@或*,则依次对每个位置参数应用替换操作,扩展为结果列表。如果参数是一个带有@或*的下标数组变量,那么替换操作将依次应用于数组的每个成员,扩展是结果列表。