664

对给定的输入字符串进行查找和替换的最简单方法是什么,比如在文件中abc替换为另一个字符串?XYZ/tmp/file.txt

我正在编写一个应用程序并使用 IronPython 通过 SSH 执行命令——但我不太了解 Unix,也不知道要寻找什么。

我听说 Bash 除了作为命令行界面之外,还可以是一种非常强大的脚本语言。所以,如果这是真的,我假设你可以执行这样的操作。

我可以用 bash 来做吗,实现我的目标的最简单(一行)脚本是什么?

4

17 回答 17

1119

最简单的方法是使用 sed(或 perl):

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

-i由于该选项,它将调用 sed 进行就地编辑。这可以从 bash 中调用。

如果您真的真的只想使用 bash,那么以下方法可以工作:

while IFS='' read -r a; do
    echo "${a//abc/XYZ}"
done < /tmp/file.txt > /tmp/file.txt.t
mv /tmp/file.txt{.t,}

这会遍历每一行,进行替换,然后写入临时文件(不想破坏输入)。最后的移动只是临时移动到原始名称。(为了稳健性和安全性,临时文件名不应该是静态的或可预测的,但我们不要去那里。)

对于 Mac 用户:

sed -i '' 's/abc/XYZ/g' /tmp/file.txt(请参阅下面的评论为什么)

于 2009-02-08T12:20:29.707 回答
177

文件操作通常不是由 Bash 完成,而是由 Bash 调用的程序完成,例如:

perl -pi -e 's/abc/XYZ/g' /tmp/file.txt

-i标志告诉它进行就地替换。

有关man perlrun更多详细信息,包括如何备份原始文件,请参阅。

于 2009-02-08T12:10:32.440 回答
75

当我偶然发现这个时,我很惊讶...

replace软件包附带了一个命令"mysql-server",因此如果您已安装它,请尝试一下:

# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt

# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"

有关man replace更多信息,请参阅。

于 2013-04-09T15:35:27.373 回答
69

这是一篇旧帖子,但对于任何想要使用变量的人来说,@centurian 说单引号意味着什么都不会被扩展。

获取变量的一种简单方法是进行字符串连接,因为这是通过 bash 中的并置完成的,以下应该可以工作:

sed -i -e "s/$var1/$var2/g" /tmp/file.txt
于 2015-12-07T12:48:56.783 回答
43

Bash 和其他 shell 一样,只是一个协调其他命令的工具。通常你会尝试使用标准的 UNIX 命令,但你当然可以使用 Bash 来调用任何东西,包括你自己编译的程序、其他 shell 脚本、Python 和 Perl 脚本等。

在这种情况下,有几种方法可以做到这一点。

如果您想读取一个文件,并将其写入另一个文件,同时进行搜索/替换,请使用 sed:

    sed 's/abc/XYZ/g' <infile >outfile

如果您想就地编辑文件(就像在编辑器中打开文件,编辑它,然后保存它),请向行编辑器“ex”提供说明

    echo "%s/abc/XYZ/g
    w
    q
    " | ex file

示例就像vi没有全屏模式。你可以在vi's:提示符下给它同样的命令。

于 2009-02-08T12:13:13.807 回答
36

我发现了这个线程,我同意它包含最完整的答案,所以我也添加了我的:

  1. sed并且ed非常有用......手工制作。看看@Johnny 的这段代码:

    sed -i -e 's/abc/XYZ/g' /tmp/file.txt
    
  2. 当我的限制是在 shell 脚本中使用它时,不能在内部使用任何变量来代替“abc”或“XYZ”。BashFAQ似乎至少与我的理解一致。所以,我不能使用:

    x='abc'
    y='XYZ'
    sed -i -e 's/$x/$y/g' /tmp/file.txt
    #or,
    sed -i -e "s/$x/$y/g" /tmp/file.txt
    

    但是,我们能做些什么呢?正如@Johnny 所说,使用 awhile read...但是,不幸的是,这并不是故事的结局。以下对我很有效:

    #edit user's virtual domain
    result=
    #if nullglob is set then, unset it temporarily
    is_nullglob=$( shopt -s | egrep -i '*nullglob' )
    if [[ is_nullglob ]]; then
       shopt -u nullglob
    fi
    while IFS= read -r line; do
       line="${line//'<servername>'/$server}"
       line="${line//'<serveralias>'/$alias}"
       line="${line//'<user>'/$user}"
       line="${line//'<group>'/$group}"
       result="$result""$line"'\n'
    done < $tmp
    echo -e $result > $tmp
    #if nullglob was set then, re-enable it
    if [[ is_nullglob ]]; then
       shopt -s nullglob
    fi
    #move user's virtual domain to Apache 2 domain directory
    ......
    
  3. 正如人们所看到的那样,如果nullglob设置了,当有一个包含 a 的字符串时,它的行为很奇怪*

    <VirtualHost *:80>
     ServerName www.example.com
    

    变成

    <VirtualHost ServerName www.example.com
    

    没有结束尖括号,Apache2 甚至无法加载。

  4. 这种解析应该比一次性搜索和替换要慢,但是,正如您已经看到的,在一个解析周期内有四种不同的搜索模式有四个变量。

对于给定的问题假设,我能想到的最合适的解决方案。

于 2013-02-07T14:48:02.140 回答
29

您可以使用sed

sed -i 's/abc/XYZ/gi' /tmp/file.txt

如果您不知道文件名find,您可以使用:sed

find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;

在所有 Python 文件中查找和替换:

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
于 2017-01-14T09:45:22.140 回答
15

如果用“/”字符替换 URL,请小心。

如何做到这一点的一个例子:

sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"

摘自:http ://www.sysadmit.com/2015/07/linux-remplazar-texto-en-archivos-con-sed.html

于 2015-07-27T19:08:59.727 回答
13

如果您正在处理的文件不是那么大,并且将其临时存储在变量中没有问题,那么您可以一次对整个文件使用 Bash 字符串替换 - 无需逐行检查:

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt

整个文件内容将被视为一个长字符串,包括换行符。

XYZ 可以是变量,例如$replacement,这里不使用 sed 的一个优点是您不必担心搜索或替换字符串可能包含 sed 模式分隔符(通常但不一定是 /)。一个缺点是不能使用正则表达式或 sed 的任何更复杂的操作。

于 2017-04-15T02:09:16.660 回答
12

您还可以使用该ed命令进行文件内搜索和替换:

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 

在“通过脚本编辑文件ed”中查看更多信息。

于 2009-06-14T16:37:52.863 回答
6

要以非交互方式编辑文件中的文本,您需要就地文本编辑器,例如 vim。

这是如何从命令行使用它的简单示例:

vim -esnc '%s/foo/bar/g|:wq' file.txt

这相当于前编辑器的@slim 答案,基本上是一样的。

这里有几个ex实际的例子。

将文件中的文本替换foobar

ex -s +%s/foo/bar/ge -cwq file.txt

删除多个文件的尾随空格:

ex +'bufdo!%s/\s\+$//e' -cxa *.txt

故障排除(终端卡住时):

  • 添加-V1参数以显示详细消息。
  • 强制退出:-cwq!

也可以看看:

于 2015-05-11T20:21:39.390 回答
5

尝试以下 shell 命令:

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
于 2016-05-31T23:55:34.583 回答
4

您也可以在 bash 脚本中使用 python。我在这里的一些最重要的答案并没有取得太大的成功,并且发现它不需要循环就可以工作:

#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'

s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()
于 2016-05-03T18:44:19.903 回答
2

使用 sed 命令替换文件中多个文本的最简单方法

命令 -

sed -i 's#a/b/c#D/E#g;s#/x/y/z#D:/X#g;' 文件名

在上面的命令 s#a/b/c#D/E#g 中,我将 a/b/c 替换为 D/E,然后在 ; 我们再次做同样的事情

于 2021-07-01T04:17:35.933 回答
1

您可以使用 rpl 命令。例如,您想在整个 php 项目中更改域名。

rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/  

这不是明确的原因,但它非常快速且有用。:)

于 2015-02-12T08:34:49.443 回答
1

对于 MAC 用户,以防您不阅读评论 :)

正如@Austin 所述,如果您收到Invalid command code错误消息

对于就地替换,BSD sed需要-i标志后的文件扩展名以保存到具有给定扩展名的备份文件。

sed -i '.bak' 's/find/replace' /file.txt

''如果要跳过备份,可以使用空字符串。

sed -i '' 's/find/replace' /file.txt

@Austin 的所有优点

于 2021-11-25T20:11:18.103 回答
-1

如果一起对多个文件进行更改,我们可以在一行中执行以下操作:-

user_name='whoami'
for file in file1.txt file2.txt file3.txt; do sed -i -e 's/default_user/${user_name}/g' $file; done

添加如果以防万一可能有用。

于 2022-02-02T14:13:41.373 回答