我有一个像这样的脚本:
#!/usr/bin/env bash
OLD_PATH_BASE=./components/
NEW_PATH_BASE=../../../react_components/
find . -regextype sed -regex "\./rockstart_\w\+_app/static/js/\w\+\.js" -exec sed -i "s@^\(import \w\+ from '\)$OLD_PATH_BASE\(\w\+/\w\+\.jsx';\)@\1$NEW_PATH_BASE\2@" {} \;
这符合我的预期,但是当我这样做时:
#!/usr/bin/env bash
OLD_PATH_BASE=./components/
NEW_PATH_BASE=../../../react_components/
SED_COMMAND='sed -i "s@^\(import \w\+ from '"'\)$OLD_PATH_BASE\(\w\+/\w\+\.jsx';\)@\1$NEW_PATH_BASE\2@"'"'
find . -regextype sed -regex "\./rockstart_\w\+_app/static/js/\w\+\.js" -exec $SED_COMMAND {} \;
它不起作用并给我错误:
sed: -e expression #1, char 1: unknown command: `"'
即使我echo $SED_COMMAND
,它显示正确的命令。什么错了
答案 0 :(得分:3)
数组将起作用:
#!/usr/bin/env bash
old_path_base=./components/
new_path_base=../../../react_components/
# this is totally unnecessary, but IMHO makes your code easier to read
# ...huge long lines being unweildy by nature, after all.
sed_pieces=(
's'
"^\(import \w\+ from '\)${old_path_base}\(\w\+/\w\+\.jsx';\)"
"\1${new_path_base}\2"
'' # flags; empty set
)
# ...using an array for sed_command is the important part:
IFS='@' # this makes "${array[*]}" combine pieces with @s
sed_command=( sed -i "${sed_pieces[*]}" )
find . -regextype sed \
-regex "\./rockstart_\w\+_app/static/js/\w\+\.js" \
-exec "${sed_command[@]}" {} +
说明:
扩展字符串不加引号(如在失败的尝试中)不通过完整的解析器运行扩展结果,而是仅通过字符串拆分和glob-expansion阶段;因此,报价不会被解析和消费。这是一个功能,而不是一个错误 - 如果每个扩展运行完整的解析器,在shell中编写安全代码实际上是不可能的。请阅读BashFAQ #50以获取有关手头行为和最佳做法解决方法的完整说明。
提供更简单,更简单的例子:
a_command='touch "hello world"'
$a_command
...实际上会创建两个文件:一个名为"hello
,另一个名为world"
;这是因为经过的唯一处理步骤$a_command
是字符串拆分(基于空格拆分为单词)和glob扩展(评估该拆分过程创建的每个项目以查看它是否为glob表达式,并将其替换为匹配文件列表(如果是这样)。
-exec ... {} +
将多个输入文件名传递给exec
'd命令的每次调用;因此,在允许的情况下提高效率(这肯定是这种情况,因为支持sed
扩展名的任何-i
也支持多个输入文件。)
答案 1 :(得分:1)
我想最简单的方法就是在这里使用一个函数。
#!/usr/bin/env bash=
#Below function wraps the whole of sed processing part
sed_fun()
{
OLD_PATH_BASE=./components/
NEW_PATH_BASE=../../../react_components/
sed -i "s@^\(import \w\+ from '\)$OLD_PATH_BASE\(\w\+/\w\+\.jsx';\)@\1$NEW_PATH_BASE\2@" "$@"
}
export -f sed_fun
find . -regextype sed -regex "\./rockstart_\w\+_app/static/js/\w\+\.js" -exec bash -c 'sed_fun "$0"' {} \;
或使用数组:
sed_command=(sed -i "s@^\(import \w\+ from '\)$OLD_PATH_BASE\(\w\+/\w\+\.jsx';\)@\1$NEW_PATH_BASE\2@")
find . -regextype sed -regex "\./rockstart_\w\+_app/static/js/\w\+\.js" -exec bash -c 'sed_fun "$@"' _ {} \+
注意:作为评论中提及的@Charles Duffy,对应用程序使用完全大写变量不是一个好习惯,因为这些变量通常是为系统保留的。
<强>参考强>
find
[ Complex Actions ],了解-exec bash -c 'sed_fun "$0"' {} \;