无法让 sed 使用变量和引号

无法让 sed 使用变量和引号

我准备写一个 shell 脚本来替换这一行:

exec "$progdir/$program" ${1+"$@"}

和:

exec qemu-arm -L /mnt/c/git/build/linux_arm7/build_arm7/sysroot "$progdir/$program" ${1+"$@"}

在一个文件中。 /mnt/c/git/build/linux_arm7/build_arm7现在位于名为 的变量中BUILD_DIRECTORY。无论我尝试什么(引号、不同的分隔符),我总是以变量而不是替换结束。例如我尝试过这个:

#!/bin/bash
sed_test()
{
    sed -i 's|exec "\$progdir\/\$program" \${1+"\$@"}|exec qemu-arm -L ${BUILD_DIRECTORY}\/sysroot "\$progdir\/\$program" \${1+"\$@"}|g' ${BUILD_DIRECTORY}/file
}

并在文件中得到了这个:

exec qemu-arm -L ${BUILD_DIRECTORY}/sysroot "$progdir/$program" ${1+"$@"}

如何正确地做到这一点?

答案1

  • ${BUILD_DIRECTORY}引用防止变量扩展
  • g不需要最终的
  • 你逃避太多

如果 BUILD_DIRECTORY 变量中没有空间,请使用

sed -i 's|exec "$progdir/$program" ${1+"$@"}|exec qemu-arm -L '${BUILD_DIRECTORY}'/sysroot "$progdir/$program" ${1+"$@"}|'  ${BUILD_DIRECTORY}/file

注意周围的单引号${BUILD_DIRECTORY}

如果 BUILD_DIRECTORY 中有空间(比如说linux arm7),请使用中继字符串(命令拆分)

sed -e 's|exec "$progdir/$program" ${1+"$@"}|exec qemu-arm -L BUILD_DIRECTORY/sysroot "$progdir/$program" ${1+"$@"}|'  
   -e "s|BUILD_DIRECTORY|${BUILD_DIRECTORY}|" 
   "${BUILD_DIRECTORY}/file"

屈服

exec qemu-arm -L /mnt/c/git/build/linux arm7/build_arm7/sysroot "$progdir/$program" ${1+"$@"}

答案2

zshperl

SRC='exec "$progdir/$program" ${1+"$@"}' \
  DST='exec qemu-arm -L '${(qq)BUILD_DIRECTORY}' "$progdir/$program" ${1+"$@"}' \
  perl -pi -e 's/\Q$ENV{SRC}\E/$ENV{DST}/g' -- "$BUILD_DIRECTORY/file"

由于您正在编辑的显然是类似 Bourne 的 shell 代码,因此您需要确保结果是有效的 shell 代码。因此,您需要$BUILD_DIRECTORY以一种方式插入变量的内容,即当sh结果解析时,该值会作为一个参数传递给该值qemu-arm,即使它包含 shell 语法中的特殊字符,例如;?'、 空格。 。

最好的方法是用单引号表示它,这是最安全的引用模式sh,如果变量包含单引号字符,请将它们插入到\'单引号之外。这就是qq参数扩展标志在 中的作用zsh。例如,它变成:

  • 将空字符串放入''
  • a;b进入'a;b'
  • a'b进入'a'\''b'

$BUID_DIRECTORY扩展传递给的代码内部的值sed意味着您引入了代码sed注入漏洞,除非您转义了该上下文中的特殊字符。另请注意-i(某些sed实现已从 参考资料复制perl)不是标准的。

使用perl代替意味着:

  • 你可以-i便携式使用
  • 您不需要转义 中的正则表达式运算符,$SRC因为我们可以使用\Q/\E来转义。
  • 你也不需要逃避替换。

答案3

使用变量插入 sed 代码的方法是首先转义 shell 可验证的内容,具体取决于它是在s///命令的 LHS 还是 RHS 中使用。

在您的场景中,构建变量将放置在 rhs.因此,我们需要转义& \ and :字符,因为在实际的 sed 代码中我们使用s:::作为分隔符。另外,如果构建变量是多行的,我们也会转义其中的换行符。由于变量将被单引号括起来,我们还需要将所有单引号更改为'\''以防构建变量中包含单引号。

BUILD_DIRECTORY='/mnt/c/git/build/linux_arm7/build_arm7'

BUILD_DIRECTORY_rhs=$(printf '%s\n' "${BUILD_DIRECTORY}" |
sed \
  -e 's/[\&:]/\\&/g'    \
  -e 's/'\''/&\\\\&&/g' \
  -e '$!s/$/\\/')

sed -i -e 's:^exec \("$progdir/$program" ${1+"$@"}\)$:'"exec qemu-arm -L '${BUILD_DIRECTORY_rhs}/sysroot' \\1:"  -- "${BUILD_DIRECTORY}/file"

这输出:

exec qemu-arm -L '/mnt/c/git/build/linux_arm7/build_arm7/sysroot' "$progdir/$program" ${1+"$@"}

相关内容