从Bash命令查找并替换文本文件中的内容

查找和替换给定输入字符串(例如abc)并替换为另一个字符串(例如文件/tmp/file.txt中的XYZ)的最简单方法是什么?

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

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

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

851056 次浏览

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

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

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

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

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

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

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

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

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

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

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

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

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

由于-i选项,它将调用ses进行就地编辑。这可以从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

(见下面的评论为什么)

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

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

查看更多“使用ed通过脚本编辑文件”。

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

  1. seded非常有用… 查看@Johnny的代码:

    sed -i -e 's/abc/XYZ/g' /tmp/file.txt
    
  2. When my restriction is to use it in a shell script, no variable can be used inside in place of "abc" or "XYZ". The BashFAQ seems to agree with what I understand at least. So, I can't use:

    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所说,使用while 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. As one can see if nullglob is set then, it behaves strangely when there is a string containing a * as in:

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

    这成为

    <VirtualHost ServerName www.example.com
    

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

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

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

我很惊讶当我发现这个…

有一个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

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

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

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

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

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

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

这相当于编辑器的@陈志立,基本上是一样的。

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

将文件中的文本foo替换为bar

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

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

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

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

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

另见:

  • #Vi SE的EYZ0

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

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

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

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

这是一篇旧文章,但对于任何想要使用变量的人来说,@centurian说单引号意味着不会扩展任何内容。

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

sed -i -e "s/$var1/$var2/g" /tmp/file.txt

你也可以在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()

尝试以下shell命令:

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'

您可以使用sed

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

如果您不知道文件名,可以使用findsed

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

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

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

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

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

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

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

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

命令-

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,然后在;我们再次做同样的事情

对于MAC用户,如果您没有阅读评论:)

正如@Austin所提到的,如果您收到Invalid command code错误

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

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

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

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

一切都归功于@Austin

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

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

添加如果在情况下可能是有用的。

使用vim编辑器打开文件。在命令模式下

:%s/abc/xyz/g

这是最简单的