我有一个像这样的脚本:
#!/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
,它显示正确的命令。怎么了
数组将起作用:
#!/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扩展阶段运行;因此,报价不会被解析和使用。这是一个功能,而不是错误-如果每个扩展都运行完整的解析器,则实际上无法在shell中编写安全代码。请阅读BashFAQ#50,以获取对当前行为的完整解释以及最佳实践的变通方法。
为了提供一个简短,简单的示例:
a_command='touch "hello world"'
$a_command
...实际上将创建两个文件:一个名为"hello
,一个名为world"
;这是因为唯一的处理步骤$a_command
是字符串拆分(基于空格拆分为单词)和全局扩展(评估该拆分过程创建的每个项目,以查看其是否为全局表达式,然后将其替换为匹配文件列表)如果是这样)。
-exec ... {} +
将多个输入文件名传递给exec
'd命令的每次调用;因此,它是在允许的情况下提高效率的方式(这里肯定是这种情况,因为任何sed
支持-i
扩展的文件也将支持多个输入文件)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句