如何使用命令行替换Linux中具有不同文件扩展名的多个子文件夹中的多个文件中的字符串

发布于 2025-01-10 09:42:23 字数 455 浏览 0 评论 0原文

我已经关注了这个查询@ (如何在 Linux 命令行中替换多个文件中的字符串)。

我的问题是同样的问题的延伸。

我只想检查子文件夹中的特定文件扩展名,但不是每个文件扩展名。

我已经尝试过的:

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

我的问题:它也在其他所有文件格式中发生变化。我只想搜索并替换一个文件扩展名。

请添加另一个答案,我可以更改文件的整行,而不仅仅是一个单词。

提前致谢。

I have already followed this query @ (How to replace a string in multiple files in linux command line).

My question is rather an extension of the same.

I want to check only specific file extensions in the subfolders also but not every file extension.

What I have already tried:

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

My problem: It is changing in every other file format as well. I want to search and replace only in one file extension.

Please add another answer where I can change the entire line of a file as well not just one word.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雾里花 2025-01-17 09:42:23

这是有趣的单行命令解决方案,应该解决诸如您的

find ./ -type f -name "*.cpp" -print0 | xargs -0 grep -l 'searchedString' | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i 's/searchedString/replacementString/g'

优点之类的问题:

  • 该命令正确处理带有空格和特殊字符的文件名
  • 可以精确过滤哪些文件需要搜索以及哪些文件不应该使用查找表达式
  • grep 还可以执行其他操作从这些找到的文件中过滤以仅选择其中包含搜索字符串的文件
  • 此命令还会将过滤后的文件最终被修改的控制台窗口写入(可选地可以将此信息写入某些日志文件)
  • 它递归地搜索指定的所有子目录目录

一无法完全找到类似的解决方案,该解决方案可以在有关此主题的其他线程中同时执行上述所有

操作说明:

  • ./ - 开始在当前目录中搜索。这可以替换为文件系统中的任何目录
  • -type f - 仅搜索文件(不是目录等)
  • -print0 - 将空字符附加到每个文件的末尾找到的文件名。对于将输出通过管道传输到 xargs -0 非常重要
  • xargs -0 - 将输入视为一系列以空字符结尾的字符串,并将其传递给下一个 grep 命令。这对于正确处理包含空格和特殊字符的文件名非常重要
  • grep -l 'searchedString' - 过滤输入文件以仅输出包含 searchedString 的文件名。 -l 导致输出仅包含文件名而不是文件中的匹配行,以便它们可以被接受作为 sed
  • tee /dev/tty 的输入 - 这会将 grep 输出分叉到管道中的下一个命令,并且还可以到 /dev/tty 这是控制台窗口,以查看哪些文件将被更改。 (可选)可以将此信息写入某个日志文件,如下所示: ... |三通 ~/replacement.log | tr ...
  • tr '\n' '\0' - 默认情况下 grep -l 输出用换行符分隔的文件名。因此 tr 会对 xargs -0 输入的换行符进行翻译/替换为空字符,以避免空格/特殊字符问题
  • sed -i - i 参数告诉 sed 进行更改” in-place”,即修改作为参数提供的文件,而不仅仅是在控制台窗口中写入修改后的内容,而是
  • 's/searchedString/replacementString/g' - s 代表替换/替换,g - 代表全局,即替换一行中的所有出现位置,而不仅仅是一行中的第一次出现

示例:

在所有 .cpp 和 .c 文件中将所有出现的短语 parameter_extraction 替换为 ParameterExtraction但不是在文件名中附加 _old 的 .c、.cpp 文件,例如 test_old.cpp

find ./ -type f \( \( -name "*.cpp" -o -iname "*.c" \) -a -not -iname "*_old.*" \) -print0 | xargs -0 grep -l 'parameter_extraction' | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i 's/parameter_extraction/ParameterExtraction/g'

在查找表达式中:
-o 代表逻辑或
-a 代表逻辑与
注意:在表达式左括号 \( 和结束括号 \) 之前添加一个空格非常重要,否则会出现错误

您还询问如何更改文件中的整行,而不仅仅是一个短语
方法是使用修改后的 sed 命令

如果您想仅当输入行包含搜索短语时用新的不同行替换整行您可以使用不同语法的 sed
c - 代表 cut,即用 replacementString 代替包含 searchedString 的行

find ./ -type f -name "*.cpp" -print0 | xargs -0 grep -l 'searchedString' | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i '/searchedString/c replacementLine'

或者如果您想用新的不同行替换整个匹配行您可以使用正则表达式符号 ^ 和 $
^ - 表示下一个符号之前的行开始
$ - 表示前一个符号之后的行尾
因此整行可以与 ^line$ 正则表达式短语匹配

find ./ -type f -name "*.cpp" -print0 | xargs -0 grep -l '^searchedLine
 | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i 's/^searchedLine$/replacementLine/g'

Here is interesting one-line command solution that should solve problems like Yours

find ./ -type f -name "*.cpp" -print0 | xargs -0 grep -l 'searchedString' | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i 's/searchedString/replacementString/g'

Advantages:

  • this command correctly handles file names with whitespaces and special characters
  • it is possible to precisely filter which files need to be searched and which shouldn't using find expressions
  • grep does additional filtering from these found files to select only files among them which contain searched string
  • this command also writes out to console window which filtered files have been modified in the end (optionally can write this information to some log file)
  • it searches recursively all subdirectories from specified directory

I couldn't quite find a similar solution which does simultaneously all above in other threads on this topic

Explanation:

  • ./ - start searching in current directory. This can be replaced by any directory in file system
  • -type f - search only for files (not directories, etc.)
  • -print0 - append null character to the end of each found file name. Important for piping the output to xargs -0
  • xargs -0 - treat input as a serie of strings ending with null character and pass it to the next grep command. This is important to correctly handle file names with whitespaces and special characters
  • grep -l 'searchedString' - filter input files to output only file names that contain searchedString. -l causes output to contain only filenames instead of matched lines in files so that they can be accepted as input for sed
  • tee /dev/tty - this does the fork of grep output to next command in pipeline and also to /dev/tty which is the console window to see what files are going to be changed. Optionally can write this information to some log file instead like that: ... | tee ~/replacement.log | tr ...
  • tr '\n' '\0' - by default grep -l outputs file names separated with new lines. So tr does translation/replacement of newlines with null characters for input for xargs -0 to avoid whitespaces/special characters problem
  • sed -i - i parameter tells sed to make changes "in-place", that is to modify files provided as argument not just write modified content in console window instead
  • 's/searchedString/replacementString/g' - s stands for substitution/replacement, g - stands for global, that is replacing all occurrences in a line not only first occurrence in a line

Example:

replacing all occurrences of the phrase parameter_extraction with ParameterExtraction in all .cpp and .c files but not the .c, .cpp files that have been appended _old in the file names like test_old.cpp

find ./ -type f \( \( -name "*.cpp" -o -iname "*.c" \) -a -not -iname "*_old.*" \) -print0 | xargs -0 grep -l 'parameter_extraction' | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i 's/parameter_extraction/ParameterExtraction/g'

In find expressions:
-o stands for logical or
-a stands for logical and
note: it is important to add a space after expression opening brackets \( and before ending brackets \) otherwise there will be an error

You also asked how to change the entire lines in a file, not just one phrase
The way to do that is to use modified sed command

If You want to replace whole lines with new different lines only when input lines contain the searched phrase You can use sed with different syntax
c - stands for cut, that is to put a replacementString in place of lines that contained searchedString

find ./ -type f -name "*.cpp" -print0 | xargs -0 grep -l 'searchedString' | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i '/searchedString/c replacementLine'

Or if You want to replace whole matched lines with new different lines You can use regex symbols ^ and $
^ - denotes start of the line before the next symbol
$ - denotes end of the line after the previous symbol
So whole lines can be matched with ^line$ regex phrase

find ./ -type f -name "*.cpp" -print0 | xargs -0 grep -l '^searchedLine
 | tee /dev/tty | tr '\n' '\0' | xargs -0 sed -i 's/^searchedLine$/replacementLine/g'
瑾兮 2025-01-17 09:42:23
  1. 最简单的解决方案是使用复杂的 grep 命令:

    grep -rli --include="*.html" --include=".json" '旧词' *

此解决方案的缺点。是您没有明确控制扫描哪些文件。

  1. 更好的建议是调整 find 命令来查找所需的文件。

使用 RegExp 过滤选项 -regex 来过滤文件名。

因此,您验证扫描了正确的文件。

然后将 find 命令结果提供给 grep 扫描列表。

示例:

假设您正在查找文件扩展名 txt pdf html

搜索路径从 /home/user/data 开始

 find /home/user/data -regex ".*\.\(html\|txt\|pdf\)$"

假设您找到文件后, 。可以通过 grep 匹配上述 find 命令中的每个文件:

 grep -rli 'old-word' $( find /home/user/data -regex ".*\.\(html\|txt\|pdf\)$" ) 
  1. Simplest solution is to use complex grep command:

    grep -rli --include="*.html" --include=".json" 'old-word' *

The disadvantage of this solution. Is that you do not have clear control which files are scanned.

  1. Better suggesting to tune a find command to locate your desired files.

Using RegExp filtering option -regex to filter file names.

So you verify the correct files are scanned.

Than feed the find command result to grep scanning list.

Example:

Assuming you are looking for file extensions txt pdf html .

Assuming your search path begins in /home/user/data

 find /home/user/data -regex ".*\.\(html\|txt\|pdf\)
quot;

Once you have located your files. It is possible to grep match each file from the the above find command:

 grep -rli 'old-word' $( find /home/user/data -regex ".*\.\(html\|txt\|pdf\)
quot; ) 
深空失忆 2025-01-17 09:42:23

我希望有人会利用这条编码线,即使答案或解决方案太晚了。
这是始终适合我的命令行。

find ./ -type f | xargs sed -i 's/old-word/new-word/g'

享受。 :)

I hope someone will take advantage of this coding line even if the answer or solution is too,late.
this is the command line that always works for me.

find ./ -type f | xargs sed -i 's/old-word/new-word/g'

Enjoy. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文