在文件 /tmp/file.txt
中查找和替换给定输入字符串(例如 abc
)并替换为另一个字符串(例如 XYZ
)的最简单方法是什么?
我正在编写一个应用程序并使用 IronPython 通过 SSH 执行命令——但我不太了解 Unix,也不知道要寻找什么。
我听说 Bash 除了作为命令行界面之外,还可以是一种非常强大的脚本语言。所以,如果这是真的,我假设你可以执行这样的操作。
我可以用 bash 来做吗,实现我的目标的最简单(一行)脚本是什么?
最简单的方法是使用 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
(请参阅下面的评论为什么)
文件操作通常不是由 Bash 完成,而是由 Bash 调用的程序完成,例如:
perl -pi -e 's/abc/XYZ/g' /tmp/file.txt
-i
标志告诉它进行就地替换。
有关更多详细信息,包括如何备份原始文件,请参阅 man perlrun
。
perl -pi -e 's/chdir (?:\\/[\\w\\.\\-]+)+/chdir blah/g' text
,但我一直收到错误,在 -e 第 1 行不推荐使用模式和后面的单词之间没有空格。不匹配的(在正则表达式中;在 m/(chdir)() 中由 <-- HERE 标记)( <-- 这里 ?:\\/ 在 -e 第 1 行。
当我偶然发现这个时,我很惊讶...
"mysql-server"
软件包附带了一个 replace
命令,因此如果您已安装它,请尝试一下:
# 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
。
replace
是一个有用的独立工具,MySQL 人员应该单独发布它并依赖它 b) replace
需要一些 MySQL o_O 无论哪种方式,安装 mysql-server 以获取替换将做错事:)
mysql-server
软件包。正如@rayro 所指出的,replace
是其中的一部分。
这是一篇旧帖子,但对于任何想要使用变量的人来说,@centurian 说单引号意味着什么都不会被扩展。
获取变量的一种简单方法是进行字符串连接,因为这是通过 bash 中的并置完成的,以下应该可以工作:
sed -i -e "s/$var1/$var2/g" /tmp/file.txt
sed "s/\"$li\"/- [x]\"\${li:5}\"/" $dat
ang get sed unterminated `s' command
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
的 :
提示符下给它同样的命令。
for
循环中一次做一个。
for f in report*.txt; do echo "%s/abc/XYZ/g \n w \n q \n" | ex file; done
简洁明了。为什么要将 shell 已有的功能放入 ex
中?
我发现了这个线程,我同意它包含最完整的答案,所以我也添加了我的:
sed 和 ed 非常有用……手动。从@Johnny 看这段代码: sed -i -e 's/abc/XYZ/g' /tmp/file.txt 当我的限制是在 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 所说,使用一段时间阅读......但不幸的是,这并不是故事的结局。以下对我很有效: #edit user's virtual domain result= #if nullglob is set then, unset it temporary is_nullglob=$( shopt -s | egrep -i '*nullglob' ) if [[ is_nullglob ]];然后 shopt -u nullglob fi while IFS= read -r line; do line="${line//'
对于给定的问题假设,我能想到的最合适的解决方案。
sed -e "s/$x/$y/"
,它会起作用。不是双引号。如果变量中的字符串本身包含具有特殊含义的字符,则可能会造成严重混淆。例如,如果 x="/" 或 x="\"。当您遇到这些问题时,这可能意味着您应该停止尝试使用 shell 来完成这项工作。
您可以使用 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' {} \;
-i
不是“忽略大小写”,而是 -i[SUFFIX], --in-place[=SUFFIX]
(就地编辑文件(如果提供了 SUFFIX,则进行备份))
如果用“/”字符替换 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
如果您正在处理的文件不是那么大,并且将其临时存储在变量中没有问题,那么您可以一次对整个文件使用 Bash 字符串替换 - 无需逐行检查:
file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
整个文件内容将被视为一个长字符串,包括换行符。
XYZ 可以是变量,例如 $replacement
,此处不使用 sed 的一个优点是您不必担心搜索或替换字符串可能包含 sed 模式分隔符(通常但不一定是 /)。一个缺点是不能使用正则表达式或 sed 的任何更复杂的操作。
您也可以使用 ed
命令进行文件内搜索和替换:
# delete all lines matching foobar
ed -s test.txt <<< $'g/foobar/d\nw'
在“Editing files via scripts with ed
”中查看更多信息。
sed -i <pattern> <filename>
不同)。非常好!
要以非交互方式编辑文件中的文本,您需要就地文本编辑器,例如 vim。
这是如何从命令行使用它的简单示例:
vim -esnc '%s/foo/bar/g|:wq' file.txt
这相当于ex编辑器的@slim answer,基本上是一样的。
以下是几个ex
实际示例。
将文件中的文本 foo
替换为 bar
:
ex -s +%s/foo/bar/ge -cwq file.txt
删除多个文件的尾随空格:
ex +'bufdo!%s/\s\+$//e' -cxa *.txt
故障排除(终端卡住时):
添加 -V1 参数以显示详细消息。
强制退出:-cwq!。
也可以看看:
如何以非交互方式编辑文件(例如在管道中)?在 Vi SE
-V1
,要强制退出,请使用 wq!
。
尝试以下 shell 命令:
find ./ -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
sed
,请改用 sed -i''
。
您也可以在 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()
使用 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,然后在 ;我们再次做同样的事情
您可以使用 rpl 命令。例如,您想在整个 php 项目中更改域名。
rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/
这不是明确的原因,但它非常快速且有用。 :)
对于 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
添加如果以防万一可能有用。
sed
的正则表达式:s/..../..../ - Substitute
和/g - Global
invalid command code C
错误的 Mac 用户请注意... 对于就地替换,BSDsed
需要在-i
标志之后添加文件扩展名,因为它保存具有给定扩展名的备份文件。例如:sed -i '.bak' 's/find/replace/' /file.txt
您可以使用空字符串跳过备份,如下所示:sed -i '' 's/find/replace/' /file.txt
s/abc/XYZ/gi