我有一个脚本,可以搜索字符串并通过 sed 命令替换它。如果该字符串包含特殊字符,脚本将对它们进行转义(斜线除外,因为它是我当前的 sed 分隔符,而列则在 bash 行上标记字符串)。
事情是这样的:
raw_searchstring='SearchForThis';
raw_replacementstring='ReplaceWithThis';
#Escape special characters:
quoted_searchstring=$(printf %s "$raw_searchstring" | sed 's/[][()\.^$?*+]/\\&/g');
quoted_replacementstring=$(printf %s "$raw_replacementstring" | sed 's/[][()\.^$?*+]/\\&/g');
find ./ -type f -exec sed -i -r "s/$quoted_searchstring/$quoted_replacementstring/" {} \;
我在 Ubuntu 上测试了这个,效果很好。
但是,我需要在 AIX 系统上运行该脚本。由于它不支持使用 sed -i 进行内联编辑,因此我尝试了以下操作,如此处类似问题的建议(AIX 的 sed - 就地编辑):
find ./ -type f -exec sed -r 's/$quoted_searchstring/$quoted_replacementstring/' infile > tmp.$$ && mv tmp.$$ infile {} \;
这是我收到错误的地方
find: missing argument to `-exec'
find
所以我尝试使用这一行传递多个 -exec 语句:
find /home/tobias/Desktop -type f -exec sed -r 's/$quoted_searchstring/$quoted_replacementstring/' infile > tmp.$$ {} \; -exec mv tmp.$$ infile {} \;
这也不起作用:
sed: can't read infile: No such file or directory
我不确定我做错了什么。您能帮我修复这行代码或为我指出正确的方向吗?
答案1
您的尝试不起作用,因为您尝试在 执行的命令中使用 shell 运算符,例如&&
和,但您直接在命令中键入这些运算符,因此它们由调用 的 shell 执行。您的命令被解析为>
find
find
find … > tmp.$$ && mv …
例如第一次find
调用是
find ./ -type f -exec sed 's/$quoted_searchstring/$quoted_replacementstring/' infile
输出重定向到tmp.$$
.该命令还存在其他问题:infile
应该是{}
(这是找到的文件find
),并且 sed 表达式周围的单引号应该是双引号,因为您在其中使用了 shell 变量。
由于您需要在 执行的命令中使用 shell 结构find
,因此请告诉find
执行 shell。
find … -exec sh -c '…' {} \;
为了避免引用困难,请将需要引用的内容(例如 sed 表达式)作为参数传递给sh
.
find ./ -type f -exec sh -c '
sed "$0" "$1" >"$1.new" && mv "$1.new" "$1"
' "s/$quoted_searchstring/$quoted_replacementstring/" {} \;
为了在稍微损失易读性的情况下获得轻微的性能提升,您可以使用表单-exec … {} +
和 shell 循环。
find ./ -type f -exec sh -c '
for x; do
sed "$0" "$x" >"$x.new" && mv "$x.new" "$x";
done
' "s/$quoted_searchstring/$quoted_replacementstring/" {} +
另外,如果您的 AIX 上的 版本ksh93
不是太旧,您可以使用它的递归通配符功能(在 ksh93p 中引入)。
set -G
for x in **; do
[[ -f $x ]] || continue
sed "s/$quoted_searchstring/$quoted_replacementstring/" "$x" >"$x.new" && mv "$x.new" "$x";
done
无论如何,请注意,您还需要调整字符串到正则表达式的转换以生成基本的正则表达式,因为-r
使用 ERE 的标志是 GNU 扩展。此外,您现有的代码有一些错误:您忘记引用斜杠,并且您没有在替换文本中引用正确的字符。
quoted_searchstring=$(printf %s "$raw_searchstring" | sed 's![[\/.^$*]!\\&!g');
quoted_replacementstring=$(printf %s "$raw_replacementstring" | sed -e 's![][\/&]!\\&!g' -e '!$ s!$!\\!');