从Bash命令查找和替换文本文件

Ash*_*Ash 530 ssh bash scripting ironpython replace

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

我正在编写一个应用程序并使用IronPython通过SSH执行命令 - 但我不熟悉Unix,也不知道要查找什么.

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

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

joh*_*nny 875

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

-i

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

如果你真的真的想使用bash,那么以下内容可以工作:

-i

这循环遍历每一行,进行替换,并写入临时文件(不想破坏输入).最后的移动只是临时移动到原始名称.

  • 对于获得"无效命令代码C"错误的Mac用户的注意事项...对于就地替换,BSD"sed"在`-i`标志之后需要文件扩展名,因为它保存了具有给定扩展名的备份文件.例如:`sed -i'.bak's/find/replace /'/ file.txt`您可以使用如下的空字符串跳过备份:`sed -i''s/find/replace/'/ file.txt` (84认同)
  • 提示:如果您想要不区分大小写的重复使用`s/abc/XYZ/gi` (7认同)
  • 但是,对于Solaris,我不存在sed的-i参数(我会考虑其他一些实现),所以请记住这一点.只花了几分钟搞清楚...... (5认同)
  • 除了调用mv与使用sed一样非'非Bash'.我差点说回声,但它是内置的shell. (3认同)
  • 自我注意:关于`sed`的正则表达式:`s /..../..../ - 替换`和`/ g - 全局` (2认同)
  • Ps:对我来说,这个变体的速度提高了1/3:`对于一个in``猫hosts.txt \`; do echo $ {a // abc/XYZ}; 完成> hosts.txt.t`) (2认同)
  • @BorisD.Teoharov “i” 标志是非标准的;但如果你的“sed”有它,那就太好了。Perl 在每个版本中都应该有这个标志,但它本身是非标准的。 (2认同)

Aln*_*tak 159

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

perl -pi -e 's/abc/XYZ/g' /tmp/file.txt
Run Code Online (Sandbox Code Playgroud)

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

有关man perlrun详细信息,请参阅参考资料,包括如何备份原始文件.

  • 我的纯粹主义者说你不能确定Perl将在系统上可用.但现在这种情况很少发生.也许我正在显示我的年龄. (33认同)
  • 你能展示一个更复杂的例子吗?比如用"chdir/blah2"替换"chdir/blah"之类的东西.我试过`perl -pi -e's/chdir(?:\\/[\\ w \\.\\ - ] +)+/chdir blah/g'text`,但我一直收到错误模式和后续单词之间的空格在-e第1行弃用.不匹配(在正则表达式中;用< - HERE在m /(chdir)()中标记(< - HERE?:\\/at -e第1行. (2认同)

小智 67

我很惊讶因为我偶然发现了这个......

有一个"替换"命令随包"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"
Run Code Online (Sandbox Code Playgroud)

请参阅man替换更多内容...

  • 这里有两件事是可能的:a)`replace`是一个有用的独立工具,MySQL人应该单独发布它并依赖它b)`replace`需要一些MySQL o_O无论哪种方式,安装mysql-server来获得替换将做错了:) (10认同)
  • “警告:不建议使用replace,并且将在以后的版本中将其删除。” (2认同)
  • 注意不要在 Windows 上运行 REPLACE 命令!在 Windows 上,REPLACE 命令用于快速复制文件。与本讨论无关。 (2认同)

zco*_*rts 46

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

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

__CODE__


sli*_*lim 38

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

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

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

sed 's/abc/XYZ/g' <infile >outfile
Run Code Online (Sandbox Code Playgroud)

如果要编辑文件(就好像在编辑器中打开文件,编辑它,然后保存它),请向行编辑器'ex'提供说明

echo "%s/abc/XYZ/g
w
q
" | ex file
Run Code Online (Sandbox Code Playgroud)

Ex就像没有全屏模式的vi.您可以使用与vi'''提示相同的命令.


小智 32

在其他人中找到了这个帖子,我同意它包含最完整的答案,所以我也添加了我的:

1)sed和ed非常有用......手工制作!!! 看看@Johnny的这段代码:

sed -i -e 's/abc/XYZ/g' /tmp/file.txt
Run Code Online (Sandbox Code Playgroud)

2)当我的限制是通过shell脚本使用它时,没有变量可以用来代替abc或XYZ!似乎与我至少理解的一致.所以,我不能用:

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
Run Code Online (Sandbox Code Playgroud)

但是,我们能做什么?至于@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
......
Run Code Online (Sandbox Code Playgroud)

3)因为可以看到是否设置了nullglob,当有一个包含*的字符串时它会表现得很奇怪

<VirtualHost *:80>
 ServerName www.example.com
Run Code Online (Sandbox Code Playgroud)

变成了

<VirtualHost ServerName www.example.com
Run Code Online (Sandbox Code Playgroud)

没有结束角括号,Apache2甚至无法加载!

4)这种解析应该比单击搜索和替换慢,但是,正如您已经看到的,4个不同的搜索模式有4个变量在一个解析周期中运行!

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

  • 在你的(2) - 你可以做`sed -e"s/$ x/$ y /"`,它会起作用.不是双引号.如果变量中的字符串包含具有特殊含义的字符,则会非常混淆.例如,如果x ="/"或x ="\".当你遇到这些问题时,这可能意味着你应该停止尝试使用shell来完成这项工作. (11认同)

MMP*_*vin 20

你可以使用sed

sed -i 's/abc/XYZ/gi' /tmp/file.txt
Run Code Online (Sandbox Code Playgroud)

使用-i用于忽略大小写,如果你不知道要查找的文本是abcABCAbC

您可以使用find,sed如果您现在不使用您的文件名:

 find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;
Run Code Online (Sandbox Code Playgroud)

查找并替换所有python文件:

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
Run Code Online (Sandbox Code Playgroud)

  • `-i` 不是“忽略大小写”,它是 `-i[SUFFIX], --in-place[=SUFFIX]` (就地编辑文件(如果提供了 SUFFIX,则进行备份)) (2认同)

小智 12

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

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 
Run Code Online (Sandbox Code Playgroud)

bash-hackers网站上查看更多信息

  • 此解决方案独立于GNU/FreeBSD(Mac OSX)不兼容性(与`sed -i <pattern> <filename>`不同).非常好! (3认同)

小智 9

如果用"/"字符替换URL,请务必小心.

如何做到的一个例子:

sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"
Run Code Online (Sandbox Code Playgroud)

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


joh*_*aff 9

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

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
Run Code Online (Sandbox Code Playgroud)

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

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

  • 如果要在要替换的字符串中放置一个制表符,则可以使用Bash的“美元单引号”语法,因此制表符由$'\ t'表示,并且可以执行$ echo'tab'$ '\ t''分隔的&gt;测试文件; $ file_contents = $(&lt;testfile); $ echo“ $ {file_contents // $'\ t'/ TAB}”; tabTAB分隔的` (2认同)

ken*_*orb 5

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

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

vim -esnc '%s/foo/bar/g|:wq' file.txt
Run Code Online (Sandbox Code Playgroud)

这相当于编辑器的@slim答案,基本上是同一回事。

这里是一些ex实际的例子。

替换文字foobar文件中:

ex -s +%s/foo/bar/ge -cwq file.txt
Run Code Online (Sandbox Code Playgroud)

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

ex +'bufdo!%s/\s\+$//e' -cxa *.txt
Run Code Online (Sandbox Code Playgroud)

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

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

也可以看看:


小智 5

尝试以下shell命令:

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
Run Code Online (Sandbox Code Playgroud)

  • 这是对“我怎么也偶然地所有子目录中的所有文件”的一个很好的答案,但这似乎不是这里要问的。 (3认同)