防止在echo参数中扩展\c

3
我正在编写一个使用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),但我也可以使用bashzsh


希望能够查看实际数据以及期望的输出/结果,这会有所帮助。 - markp-fuso
2
请注意,echo的行为极不可靠;它不仅在不同的shell之间有所不同,而且在每个shell的运行时配置之间也有所不同(例如,在bash中,设置xpg_echoposix标志,或者将您的环境变量设置为启用它们,echo会突然执行不同的操作)。如果您想要定义良好、一致的行为,请使用printf——正如POSIX标准对echo的建议!Stephane在为什么printfecho更好?上的出色回答值得一读。 - Charles Duffy
2
具体来说,请参阅 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html 的“应用使用”部分,作为上述断言的支持,即 POSIX 标准明确建议使用 printf 而不是 echo。(下面的“基本原理”部分描述了我们如何陷入这种情况)。 - Charles Duffy
3个回答

2

你可以尝试使用cat代替echo

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

这里有一个非常好的“here-docs”(嵌入文本)的解释:链接 - Paul Hodges

0
命令行使用第一个斜杠引用第二个斜杠。如果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 string"。

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"

0
#!/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 "\\\\"

1
即使解释器已知为bash,这也不是可靠的真相 - echo可以执行额外的反斜杠转义序列转换,具体取决于xpg_echoposix标志的值,这些标志可以由父进程导出正确的环境变量或在编译时设置。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接