【问题标题】:Prevent expansion of \c in echo argument防止在 echo 参数中扩展 \c
【发布时间】:2020-09-13 18:42:29
【问题描述】:

我正在用 echo 构建一个 shell 脚本。我有类似的东西:

echo "sed -i \"\\|charlie\.url\\s*=\\s*.*|c\\charlie.url = ${CHARLIE_URL}\" foo.conf" >> bar.sh

即将 foo.conf 中包含当前 charlie.url 的行替换为具有新 url 的新行.

我希望 bar.sh 的输出为

sed -i "\|charlie\.url\s*=\s*.*|c\charlie.url = ${CHARLIE_URL}" foo.conf

尽管如此,c\\charlie 被解释为 c \c harlie,而不是 c\charlie,生成以下输出:

sed -i "\|charlie\.url\s*=\s*.*|c

我发现我可以通过使用单引号而不是双引号来防止这种情况,但在这种情况下,${CHARLIE_URL}(我确实需要扩展)不会得到扩展。

我的 echo 参数应该是什么样子?

我正在使用 dash(在 Ubuntu 下是#!/bin/sh),但我也可以使用 bash 或 zsh。

【问题讨论】:

  • 如果我们能看到实际数据以及所需的输出/结果会有所帮助
  • 请注意echo的行为极其不可靠;它不仅在 shell 之间变化,而且在每个 shell 的运行时配置之间变化(f/e,在 bash 中,设置 xpg_echo 或 posix 标志,或者将您的环境变量设置为启用它们,echo 会突然做一些事情不同的)。请改用printf——正如echo 的POSIX 标准所建议的那样! -- 如果你想要定义明确、一致的行为。 Stephane 在Why is printf better than echo? 上的出色回答值得一读。
  • ...特别是,请参阅pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html 的应用程序部分,作为上述断言的支持,即echo 的 POSIX 标准明确建议使用printf。 (下面的基本原理部分描述了我们是如何陷入这种境地的)。

标签: bash shell sh zsh


【解决方案1】:

你可以试试echo,而不是cat:

cat << EOF >> bar.sh
sed -i "\|charlie\.url\s*=\s*.*|c\charlie.url = ${CHARLIE_URL}" foo.conf
EOF

【讨论】:

  • 这里文档here的很好的细分。
【解决方案2】:
#!/bin/bash

# bash will expand content within "" and stuff like $URL gets expanded
# also double-backslash reduces to a single; bash wouldn't expand stuff within ''

URL="https..."
echo double: "c\\charlie.url, URL $URL"
echo single: 'c\\charlie.url, URL $URL'

# if you need to output a \\
echo "\\\\"

【讨论】:

  • 这并不可靠,即使使用已知为 bash 的解释器 - echo 可以执行额外的反斜杠转义序列转换层,具体取决于 xpg_echo 的值和posix 标志,可以由导出正确环境变量的父进程设置,也可以在编译时设置。
【解决方案3】:

命令行使用你的第一个斜杠来引用你的第二个。如果CHARLIE_URL=foo,你的echo实际上是在输出

sed -i "\|charlie\.url\s*=\s*.*|c\charlie.url = foo" foo.conf

尝试使用单引号,但在变量周围关闭/打开它们。

echo 'sed -i "\\|charlie\.url\\s*=\\s*.*|c\\charlie.url = '"${CHARLIE_URL}"'" foo.conf'

这会产生

sed -i "\\|charlie\.url\\s*=\\s*.*|c\\charlie.url = foo" foo.conf

如前所述,您还可以引用引用斜线的斜线,然后引用另一个斜线引用的斜线,以便后续迭代将它们归结为您想要的......但这通常是一团糟,并导致倾斜牙签综合症。

已经有人提出了很好的 here-doc 建议,所以我不会重复,但您也可以使用我通常更喜欢的“here 字符串”。

cat <<< "sed -i '\|charlie\.url\s*=\s*.*|c\charlie.url = ${CHARLIE_URL}' foo.conf"

假设您想要将 $CHARLIE_URL 的文字值输出到您的脚本中,我将脚本中的双引号切换为单引号。如果您希望脚本使用在运行时分配的任何值的变量,那么也引用它 -

cat <<< "sed -i '\|charlie\.url\s*=\s*.*|c\charlie.url = \${CHARLIE_URL}' foo.conf"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 2019-07-07
    相关资源
    最近更新 更多