如何在 Linux 命令行中替换多个文件中的字符串

2024-10-12 09:08:00
admin
原创
81
摘要:问题描述:我需要替换文件夹中大量文件中的字符串,并且只能ssh访问服务器。我该怎么做?解决方案 1:cd /path/to/your/folder sed -i 's/foo/bar/g' * 出现的“foo”将被替换为“bar”。在 macOS 等 BSD 系统上,您需要...

问题描述:

我需要替换文件夹中大量文件中的字符串,并且只能ssh访问服务器。我该怎么做?


解决方案 1:

cd /path/to/your/folder
sed -i 's/foo/bar/g' *

出现的“foo”将被替换为“bar”。

在 macOS 等 BSD 系统上,您需要提供备份扩展,-i '.bak'否则根据手册页“可能会出现损坏或部分内容的风险”。

cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *

解决方案 2:

与Kaspar 的答案类似,但使用 g 标志来替换一行上的所有出现的内容。

find ./ -type f -exec sed -i 's/old_string/new_string/g' {} ;

对于全局不区分大小写:

find ./ -type f -exec sed -i 's/old_string/new_string/gI' {} ;

忽略.git目录:

find . -not -path '*/.git/*' -name '*.rb'  -exec sed -i 's/old_string/new_string/g' '{}' ;

解决方案 3:

@kev 的答案很好,但只影响直接目录中的文件。下面的示例用于grep递归查找文件。它每次都对我有用。

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

命令分解

grep -r: --recursive,递归读取每个目录下的所有文件。

grep -l: --print-with-matches,打印每个匹配的文件的名称,而不是打印匹配的行。

grep -i: --ignore-case

xargs: 将 STDIN 转换为参数,遵循此答案。

xargs -i@ ~command contains @~: 要在特定位置使用的参数的占位符~command~@符号是一个可以用任何字符串替换的占位符。

sed -i:就地编辑文件,无需备份。 :用

sed s/regexp/replacement/替换匹配的字符串。:全局,对每个匹配进行替换,而不仅仅是第一个匹配。regexp`replacement`

sed s/regexp/replacement/g

解决方案 4:

这个问题已经列出了几个标准答案。通常,您可以使用find递归列出文件,然后使用sedperl执行操作。

反向链接

对于大多数快速使用,您可能会发现命令rpl更容易记住。

在所有文件上替换foo为:bar`.txt`

rpl -v foo bar '*.txt' 

模拟在所有文件中foo.*递归替换正则表达式:bar`.txt`

rpl --dry-run 'foo.*' bar '**/*.txt'

您可能需要安装它(apt-get install rpl或类似的东西)。

代表

然而,对于涉及正则表达式和反向替换、文件重命名以及搜索和替换的更棘手的工作,我知道的最通用和最强大的工具是repren,这是我之前为一些棘手的重命名和重构任务编写的一个小 Python 脚本。您可能更喜欢它的原因是:

  • 支持文件重命名以及文件内容的搜索和替换。

  • 在执行搜索和替换之前查看更改。

  • 支持具有反向替换、全词、不区分大小写和保留大小写(替换 foo -> bar、Foo -> Bar、FOO -> BAR)模式的正则表达式。

  • 适用于多种替换,包括交换(foo -> bar 和 bar -> foo)或非唯一替换集(foo -> bar,f -> x)。

要使用它,pip install repren请查看 README中的示例。

解决方案 5:

这对我有用:

find ./ -type f -exec sed -i 's/string1/string2/' {} ;

然而,事实并非如此:sed -i 's/string1/string2/g' *。也许“foo”不应该是string1,“bar”不应该是string2。

解决方案 6:

要替换多个文件中的字符串,您可以使用:

grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'

例如

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

来源博客

解决方案 7:

假设您想要在多个文件中搜索字符串search并将其替换为replace,这是我久经考验的单行公式:

grep -RiIl 'search' | xargs sed -i 's/search/replace/g'

快速 grep 解释:

  • -R- 递归搜索

  • -i- 不区分大小写

  • -I- 跳过二进制文件(您想要文本,对吗?)

  • -l- 打印一个简单的列表作为输出。其他命令需要

然后将 grep 输出通过管道传输到 sed(通过 xargs),用于实际替换文本。该-i标志将直接更改文件。将其删除,以获得一种“试运行”模式。

解决方案 8:

要替换文件中的路径(避免转义字符),您可以使用以下命令:

sed -i 's@old_path@new_path@g'

@ 符号表示应忽略后续字符串中的所有特殊字符。

解决方案 9:

如果字符串中包含正斜杠(/),则可以将分隔符更改为“+”。

find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +

该命令将在当前目录中递归运行。

解决方案 10:

如果你有文件列表,你可以使用

replace "old_string" "new_string" -- file_name1 file_name2 file_name3

如果你拥有所有文件,则可以使用

replace "old_string" "new_string" -- *

如果你有带扩展名的文件列表,你可以使用

replace "old_string" "new_string" -- *.extension

解决方案 11:

“您也可以使用 find 和 sed,但我发现这行 perl 代码运行得很好。

perl -pi -w -e 's/search/replace/g;' *.php
  • -e 表示执行下面一行代码。

  • -i 表示就地编辑

  • -w 写警告

  • -p 循环

“(摘自http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php

我最好的结果来自使用 perl 和 grep (以确保文件具有搜索表达式)

perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )

解决方案 12:

第一行出现的“foo”将被替换为“bar”。您可以使用第二行来检查。

grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c

解决方案 13:

在 MacBook Pro 上,我使用了以下命令(受https://stackoverflow.com/a/19457213/6169225启发):

sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *

-i ''将确保您不进行备份。

-e用于现代正则表达式。

解决方案 14:

在找到这个问题(和答案)之前,我确实想出了自己的解决方案。我搜索了“replace”、“several”和“xml”的不同组合,因为那是我的应用程序,但没有找到这个特定的组合。

我的问题:我有包含测试用例数据的 spring xml 文件,其中包含复杂对象。java 源代码的重构更改了许多类,但并不适用于 xml 数据文件。为了保存测试用例数据,我需要更改分布在多个目录中的所有 xml 文件中的所有类名。同时保存原始 xml 文件的备份副本(尽管这不是必须的,因为版本控制可以在这里拯救我)。

我正在寻找find+的某种组合sed,因为它在其他情况下对我有用,但不能同时进行多次替换。

然后我找到了ask ubuntu response并且它帮助我建立了命令行:

find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} ;

而且它运行完美(好吧,我的情况有六个不同的替换)。但请注意,它将触及当前目录下的所有 *.xml 文件。因此,如果您对版本控制系统负责,您可能希望先进行过滤,然后仅传递给sed那些实际具有您想要的字符串的文件;例如:

find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} ; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} ;

解决方案 15:

真的很差劲,但我无法让任何 sed 命令在 OSX 上正常工作,所以我做了这个愚蠢的事情:

:%s/foo/bar/g
:wn

^- 将这三行复制到我的剪贴板(是的,包括结束的换行符),然后:

六*

并按住 command-v 直到它显示没有剩余文件。

愚蠢...黑客...有效...

解决方案 16:

我只想添加一条注释来同时做两件事 - 找到一个包含字符串的文件,然后使用查找“链接”方法进行替换:

find  . -type f -iname *.php -exec fgrep -l "www." {} ; -exec sed -i "s|www||g" {} ;      
  • 在这个实际案例中,从 PHP 文件中找到的 URL 中删除不合时宜的“www”。

  • 仅当在文件中找到至少一个匹配项时,才会触发“fgrep -l”,它不会产生其他输出。不要忘记“;”分隔符!

解决方案 17:

grep --include={*.php,*.html} -rnl './' -e "old" | xargs -i@ sed -i 's/old/new/g' @

解决方案 18:

多编辑命令脚本

multiedit [-n PATTERN] OLDSTRING NEWSTRING

根据Kaspar 的回答,我编写了一个 bash 脚本来接受命令行参数,并可选择限制与模式匹配的文件名。将其保存在 $PATH 中并使其可执行,然后只需使用上述命令即可。

脚本如下:

#!/bin/bash
_help="

Replace OLDSTRING with NEWSTRING recursively starting from current directory

multiedit [-n PATTERN] OLDSTRING NEWSTRING


[-n PATTERN] option limits to filenames matching PATTERN

Note: backslash escape special characters

Note: enclose STRINGS with spaces in double quotes

Example to limit the edit to python files:

multiedit -n *.py "OLD STRING" NEWSTRING
"

# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then  # if -n option is given:
        # replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
        find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} ;
else
        # replace OLDSTRING with NEWSTRING recursively in all files
        find ./ -type f -exec sed -i "s/$1/$2/" {} ;
fi

解决方案 19:

为了维护我的个人英语节点,我编写了一个实用脚本,帮助递归地替换目录下所有文件的多对旧/新字符串。

多对旧/新字符串在哈希图中进行管理。

可以通过命令行或环境变量设置目录,地图在脚本中是硬编码的,但如果有必要,您可以修改代码以从文件加载。

由于一些新功能,它需要 bash 4.2。

en_standardize.sh:

#! /bin/bash
# (need bash 4.2+,)
# 
# Standardize phonetic symbol of English.
# 
# format:
#   en_standardize.sh [<dir>]
# 
# params:
# * dir
#   target dir, optional,
#   if not specified then use environment variable "$node_dir_en",
#   if both not provided, then will not execute,
# * 
# 

paramCount=$#

# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
    echo -e "dir specified (in command):
    $1
"
    targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
    echo -e "dir specified (in environment vairable):
    $node_dir_en
"
    targetDir=$node_dir_en
else # environable not set,
    echo "dir not specified, won't execute"
    exit
fi

# check whether dir exists,
if [ -d $targetDir ]; then
    cd $targetDir
else
    echo -e "invalid dir location:
    $targetDir
"
    exit
fi

# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")

# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
    echo -e "    $key    ->    ${itemMap[$key]}"
done
echo -e '
'

# do replace,
for key in "${!itemMap[@]}"; do
    grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done

echo -e "
Done."
exit

解决方案 20:

流编辑器在使用-i开关调用时会“就地”修改多个文件,该开关以备份文件结尾作为参数。因此

sed -i.bak 's/foo/bar/g' *

foo用替换bar此文件夹中的所有文件,但不会深入到子文件夹中。但是,这会.bak为目录中的每个文件生成一个新文件。要对此目录及其所有子目录中的所有文件递归执行此操作,您需要一个助手(如find)来遍历目录树。

find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *

find如果有必要,可以通过指定进一步的参数(如)来进一步限制要修改的文件find ./ -name '*.php' -or -name '*.html' -print0


注意:GNUsed不要求文件结尾,sed -i 's/foo/bar/g' *也可以工作;FreeBSDsed要求扩展名,但允许中间有空格,因此sed -i .bak s/foo/bar/g *可以工作。

解决方案 21:

使用 ack 命令会快很多,如下所示:

ack '25 Essex' -l | xargs sed -i 's/The fox jump/abc 321/g'

另外,如果搜索结果中有空格,则需要将其转义。

解决方案 22:

如果文件包含反斜杠(通常是路径),您可以尝试如下操作:

sed -i -- 's,<path1>,<path2>,g' *

前任:

sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)

解决方案 23:

有一种更简单的方法,即使用一个简单的脚本文件:

# sudo touch /bin/replace_string_files_present_dir
# sudo chmod +x /bin/replace_string_files_present_dir

在 gedit 或您选择的编辑器中打开文件,我在这里使用 gedit。

# sudo gedit /bin/replace_string_files_present_dir

然后在编辑器中将以下内容粘贴到文件中

#!/bin/bash
replace "oldstring" "newstring" -- *
replace "oldstring1" "newstring2" -- *
#add as many lines of replace as there are your strings to be replaced for 
#example here i have two sets of strings to replace which are oldstring and 
#oldstring1 so I use two replace lines.

保存文件,关闭gedit,然后退出终端或直接关闭它然后启动它以便能够加载您添加的新脚本。

导航到您要编辑的多个文件的目录。然后运行:

#replace_string_files_present_dir

按下回车键,这将自动用正确的newstringnewstring1分别替换所有包含它们的文件中的oldstringoldstring1

它将跳过所有不包含旧字符串的目录和文件。

如果您有多个目录包含需要替换字符串的文件,这可能有助于消除繁琐的输入工作。 您所要做的就是导航到每个目录,然后运行:

#replace_string_files_present_dir

您所要做的就是确保已包含或添加了所有替换字符串,如我上面所示:

replace "oldstring" "newstring" -- *

在文件/bin/replace_string_files_present_dir的末尾。

要添加新的替换字符串,只需在终端中输入以下内容来打开我们创建的脚本:

sudo gedit /bin/replace_string_files_present_dir

不要担心添加的替换字符串的数量,如果找不到旧字符串,它们将不起作用。

解决方案 24:

我从另一篇文章(不记得是哪篇文章)中找到了这篇文章,虽然它不是最优雅的,但它很简单,作为一个 Linux 新手,它没有给我带来任何麻烦

for i in *old_str* ; do mv -v "$i" "${i/old_str/new_str}" ; done

如果有空格或其他特殊字符,请使用 \

for i in *old_str * ; do mv -v "$i" "${i/old_str /new_str}" ; done

对于子目录中的字符串使用 **

for i in **old_str * ; do mv -v "$i" "${i/old_str /new_str}" ; done

解决方案 25:

在命令行上,这取决于您尝试搜索和替换的字符串。 在我的情况下有效的方法如下:

STR="a-?fairly@complicated,*String;but%3A=fortunately&without_quotes.css"
for f in $(grep -lir "$STR" *); do sed -i "s/$STR/newstyle.css/g" $f; done

相对于find,速度提升了 66%,递归地 grep 网络蜘蛛生成的约 15k 个文件。grep-with-xargs -i@答案对我来说不起作用,可能是因为@符号。

解决方案 26:

我正在给出一个修复 Python 源中常见 shebang 错误的示例。

您可以尝试 grep/sed 方法。以下是与 GNU sed 配合使用且不会破坏 git repo 的方法:

$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \ngsed -i '' -e 's/#!/usr/bin/python/#!/usr/bin/env python/' {}

或者你可以使用greptile :)

$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .

我刚刚测试了第一个脚本,第二个脚本应该也能正常工作。小心使用转义字符,我认为在大多数情况下使用 greptile 应该更容易。当然,你可以用 sed 做很多有趣的事情,为此,最好掌握如何使用 xargs。

解决方案 27:

许多答案都让我感到困惑,因为我需要替换许多文件中的文件路径。虽然其中一个答案提到了这一点,但对我来说不起作用。我的解决方案是:

首先,生成您想要更改的文件名列表。

filelist=($(find /path/to/your/folder | xargs grep '/path/to/fix' | cut -d : -f 1 | tr '
' ' '))

上述命令的作用是,管道findgrep生成包含 的文件的名称/path/to/fix。但是,grep还会打印出找到该字符串的行,因此该cut命令会删除它并仅保留文件名。tr将换行符替换为空格,这样就可以将filelist存储为数组。

for file in "${filelist[@]}"; do sed -i.bak 's+/path/to/fix+/new/path/for/my/file+g' $file; done

sed命令借鉴了该问题的其他答案,并使用+作为分隔符而不是正常的/,因为这些/字符正在文件路径中使用。

解决方案 28:

经过研究,我找到了这个解决方案(如果您只想更改单词,则 b 表示字数限制):

$ STRING_OLD="Peter"; STRING_NEW="John"; find bin/ -type f -name '*.sh' -not -name "*.bak" -print0 | xargs -0 grep -Zl "$STRING_OLD" | xargs -t -0 sed -i.bak 's/'"$STRING_OLD"'/'"$STRING_NEW"'/g'

它适用于带有空格、制表符、换行符和非 ASCII 字符的文件名/目录。

变量 STRING_OLD 是 sed s/regexp/replacement/ 命令的正则表达式。您必须注意这一点。

您还会看到已更改的文件。它只会更改(并备份)在正则表达式中找到 STRING_OLD 的文件。其余文件保持不变(这就是我想要的)。

解决方案 29:

我使用了agthe_silver_searcher:

ag -0 -l 'old' | xargs -0 sed -ri.bak -e 's/old/new/g';

然后git clean删除 .bak 文件(rm在 git rebase 中运行时出现错误exec

git clean -f '**/*.bak';

解决方案 30:

以下命令可用于首先搜索文件并替换文件:

find . | xargs grep 'search string' | sed 's/search string/new string/g'

例如

find . | xargs grep abc | sed 's/abc/xyz/g'
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用