如何使用 sed 将标签大括号字符串替换为环境变量

How to replace a hashtag curly bracket string with an environment variable by using sed

我一直在尝试编写一个 bash 脚本,该脚本可以在目录中递归搜索并替换多个字符串,例如#{DEMO_STRING_1} 等带有环境变量,例如$sample1.

完整脚本:

#!/bin/sh

find /my/path/here -type f -name '*.js' -exec sed -i \
    -e 's/#{DEMO_STRING_1}/'"$sample1"'/g' \
    -e 's/#{DEMO_STRING_2}/'"$sample2"'/g' \
    -e 's/#{DEMO_STRING_3}/'"$sample3"'/g' \
    -e 's/#{DEMO_STRING_4}/'"$sample4"'/g' \
    -e 's/#{DEMO_STRING_5}/'"$sample5"'/g' \
    -e 's/#{DEMO_STRING_6}/'"$sample6"'/g' \
    -e 's/#{DEMO_STRING_7}/'"$sample7"'/g' \
    -e 's/#{DEMO_STRING_8}/'"$sample8"'/g' \
    {} +

我不知道如何用带有大括号的主题标签替换字符串。

我试过这个例子:sed find and replace with curly braces or Environment variable substitution in sed但我不知道如何组合它们。

我错过了什么?我还搜索了需要转义的字符,例如What characters do I need to escape when using sed in a sh script? 但同样不是我需要的字符。

特定格式抛出以下错误:

sed: bad option in substitution expression

我哪里错了?

更新:环境变量示例:

  1. https://www.example.com
  2. /示例字符串/
  3. 12345-abcd-54321-efgh
  4. base64 字符串

以上情况都是我要替换的环境变量。所有环境变量都在双引号内。

重要的是要了解环境变量引用是由 shell 扩展的,因为它准备执行命令,而不是命令本身(在本例中为 sed)。该命令只能看到展开的结果。

在您的情况下,这意味着如果任何环境变量的值包含在上下文中对 sed 有意义的字符,例如未转义的(对 sed)斜杠(/), 那么 sed 将赋予它们特殊的意义,而不是将它们解释为普通字符。例如,给定一个 sed 命令,如

sed -e "s/X/${var}/" <<EOF
Replacement:  X
EOF

,如果 $var 的值为 Y 那么输出将是

Replacement: Y

,但如果 $var 的值为 /path/to/Y,则 sed 将失败并出现与您报告的相同的错误。发生这种情况是因为 sed 命令实际上 运行 与您输入的

相同
sed -e s/X//path/to/Y

,其中包含无效的 s 指令。可能最好的选择是转义 replacement-string 字符,否则这些字符对 sed 很重要。您可以通过插入 shell 函数来做到这一点:

escape_replacement() {
  # replace all \ characters in the first argument with double backslashes.
  # Note that in order to do that here, we need to escape them from the shell
  local temp=${1//\/\\}

  # Replace all & characters with \&
  temp=${temp//&/\&}

  # Replace all / characters with \/, and write the result to standard out.
  # Use printf instead of echo to avoid edge cases in which the value to print
  # is interpreted to be or start with an option.
  printf -- "%s" "${temp//\//\/}"
}

然后脚本会像这样使用它:

find /my/path/here -type f -name '*.js' -exec sed -i \
    -e 's/#{DEMO_STRING_1}/'"$(escape_replacement "$sample1")"'/g' \
...

请注意,您可能还想使用一个 shebang 行来明确指定支持替换引用 (${parameter/pattern/replacement}) 的 shell,因为 POSIX 不需要这些,并且您可能 运行 进入一个 /bin/sh 是不支持它们的 shell 的系统。如果您愿意依赖 Bash 那么这应该反映在您的 shebang 行中。或者,您可以准备一个不依赖替换引用的 escape_replacement 函数版本。

如果您使用 perl - 您不需要转义任何内容。

使用您的 shell 变量 exported 您可以通过 perl 中的 $ENV{name} 访问它。

示例:

samples=(
    https://www.example.com
    '/sample string/'
    12345-abcd-54321-efgh
    'base64 string'
    $'multi\nline'
)

for sample in "${samples[@]}"
do
    echo '---'
    export sample
    echo 'A B #{DEMO_STRING_1} C' |
        perl -pe 's/#{DEMO_STRING_1}/$ENV{sample}/g'
done
echo '---'

输出:

---
A B https://www.example.com C
---
A B /sample string/ C
---
A B 12345-abcd-54321-efgh C
---
A B base64 string C
---
A B multi
line C
---

要添加 -i 选项,您可以:perl -pi -e 's///'