Bash、Fish:防止变量扩展

jl4*_*l4c 0 variables shell expansion fish

我计划改用 Fish 作为我的默认 shell,但遇到了一些问题。
在重写我的所有脚本之前,我想使用带有“-c”选项的 bash 重用旧脚本。
例子:

bash -c "cat <<'EOF' | tee filename >/dev/null
$SHELL
$TERM
EOF"
Run Code Online (Sandbox Code Playgroud)

即使使用'EOF',我总是得到:
/bin/fish
xterm

如果可能的话,我想避免\$SHELL在脚本中的每个变量中使用反斜杠。

fah*_*aho 5

这里的主要问题是 $SHELL 的含义并不像您想象的那样。

$SHELL 不是当前运行的 shell”,而是“用户配置的登录 shell”。

bash 和 Fish(也包括 zsh)都不会设置它,它们将从您的登录堆栈继承它。

这意味着要么您实际尝试做的事情不起作用,要么您的测试将产生误导性结果。

下一步是将鱼的参数用双引号引起来:

bash -c "..."
Run Code Online (Sandbox Code Playgroud)

这意味着在 bash 运行之前,这些变量中的变量将被Fish扩展。您可以单引号它们:

bash -c '...'
Run Code Online (Sandbox Code Playgroud)

这意味着您需要转义参数中的任何单引号,例如

bash -c 'cat <<\'EOF\' | tee filename >/dev/null                                               
$SHELL
$TERM
EOF'
Run Code Online (Sandbox Code Playgroud)

当然这会告诉 bash 做什么

cat <<'EOF' | tee filename >/dev/null
$SHELL
$TERM
EOF
Run Code Online (Sandbox Code Playgroud)

这意味着bash也不会扩展变量。如果这就是您想要的,打印文字“$SHELL”和“TERM”,那就没问题了。如果没有,您可以使用EOF不带引号的方式让bash扩展变量。

这看起来不会有任何不同,因为(见上文)$SHELL 在两个 shell 之间不会改变。您可以使用仅在 bash 中设置的变量来确认其正常工作:

bash -c 'cat <<EOF | tee filename >/dev/null                                               
$BASH_VERSION
$TERM
EOF'
Run Code Online (Sandbox Code Playgroud)

这将为您提供“文件名”中的 bash 版本。

嵌套引用和转义以及哪个 shell 扩展哪个变量的问题是我通常建议只编写 bash 脚本的原因。

使用以下内容创建一个名为“printshell”的文件:

#!/bin/bash

cat <<EOF | tee filename >/dev/null
$SHELL
$TERM
EOF
Run Code Online (Sandbox Code Playgroud)

使其可执行 ( chmod +x) 并将其放在 $PATH 中的某个位置。如果您没有合适的目录,您可以创建一个 ( mkdir) 并将其添加到 Fish 的 $PATH 中fish_add_path。这允许您无需使用完整路径即可运行它printshell,就像它是 shell 中的函数一样。

(当然,它无法访问 shell 的状态,因此您不会拥有所有变量,只有导出的变量,或者能够将cd其保留在外面。为此,您必须使用 Fish 脚本)

  • 感谢您将 SHELL 正确识别为“不是当前运行的 shell”。这种特定谬论的扩散令人痛苦。 (3认同)