为什么这个bash函数不能像直接运行那样工作?

Leo*_*lis 0 bash sed find

我写了一个函数,/etc/bashrc因为我经常使用它,但现在它似乎不起作用:

function replaceall() {
  find "$1" -type f -exec sed -i "s|$2|$3|g" {} \;
}
Run Code Online (Sandbox Code Playgroud)

直接运行时,我会做类似的事情:

find ./*/conf/production/*.conf -type f -exec sed -i "s|/home/user/sites|/var/www/vhosts|g" {} \;
Run Code Online (Sandbox Code Playgroud)

哪个工作正常.但是在使用该replaceall函数调用时它不起作用:

replaceall ./*/conf/production/*.conf "/home/user/sites" "/var/www/vhosts"
Run Code Online (Sandbox Code Playgroud)

注意:它在我使用时确实有效,replaceall . [...]这让我想知道,我是否遗漏了一些重要的语法?

Tom*_*ech 5

看起来你根本不依赖于遍历功能find,所以我建议你只使用循环的glob扩展:

replaceall() {
    for file in $1; do
        sed -i.bak "s|$2|$3|g" "$file"
    done
}
Run Code Online (Sandbox Code Playgroud)

然后调用脚本,引用每个参数:

replaceall "./*/conf/production/*.conf" "/home/user/sites" "/var/www/vhosts"
Run Code Online (Sandbox Code Playgroud)

引用每个参数可确保路径的扩展发生在函数内.我还为-i交换机添加了一个后缀,以便对每个受影响的文件进行备份,否则你的脚本非常危险!

正如评论中所提到的,这种方法仍然存在潜在问题.如果要传递包含空格的路径,则必须对其进行转义以防止分词.例如,类似的路径"./*/conf/production files/*.conf"需要在空间前面使用反斜杠"./*/conf/production\ files/*.conf".

  • 需要注意的是:单词拆分发生在路径名扩展之前,所以这不适用于第一个参数,如`"./*/conf/production files/*.conf"`.你必须逃避任何空间:`".../production\files/*.conf"`. (2认同)
  • @Leonard无后顾之忧 - 无论如何我删除了编辑摘要,因为它与未来的读者无关.顺便说一句,这远远不是我名字中最糟糕的拼写! (2认同)