重写一个在 AIX 上使用 sed -i 的 find 命令

重写一个在 AIX 上使用 sed -i 的 find 命令

我有一个脚本,可以搜索字符串并通过 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 执行。您的命令被解析为>findfind

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!$!\\!');

相关内容