我正在尝试为我的bashrc创建一个别名,如果未设置nounset
,则启用选项xtrace
和xtrace
,如果已设置,则禁用它们,允许我切换“调试模式”。
我有这个:
alias debug="[[ \$(set -o | grep xtrace) = *off ]] && (set -o nounset; set -o xtrace; echo 'Debug mode ON') || (set +o nounset; set +o xtrace; echo 'Debug mode OFF')"
我的问题是,这似乎可以查看终端输出,但是当我运行set -o
时,nounset
和xtrace
选项都没有改变。原因是两个选项都在括号()
内,因此选项不会应用于当前终端。
例如,这也不起作用(xtrace
保持关闭状态):
(set -o xtrace)
我该如何解决这个问题?有没有办法在没有括号的情况下编写上面的别名,或者从括号内应用选项?为什么会这样?
答案 0 :(得分:1)
$(…)
或(set -o ...;)
中的括号创建子shell。在子shell中进行的更改对父shell没有影响,无论是环境变量还是shell选项。
您似乎想要大声切换跟踪标记。它也被称为-x
标志,并且在$-
中可见,该参数包含当前设置的单字母标志。您还可以使用set -u
和set +u
作为set -o nounset
选项。
因此,你可以使用一些变体:
alias debug='case "$-" in
(*x*) set +xu; echo "Debug mode OFF";;
(*) set -xu; echo "Debug mode ON";;
esac'
如上所述,如果您愿意,可以将其展平为一行。还有其他方法可以使用if
和适当的条件来编写它。我仍然喜欢case
,但在使用[[
命令进行Bash之前我学习了shell脚本。
您还可以使用{
和}
代替子shell表示法。因此,对脚本进行极简主义的更改将是:
alias debug="[[ \$(set -o | grep xtrace) = *off ]] && { set -o nounset; set -o xtrace; echo 'Debug mode ON'; } || { set +o nounset; set +o xtrace; echo 'Debug mode OFF'; }"
请注意,在}
之前必须有一个“命令结束” - 实际上,这意味着换行符或分号。 {
和}
必须与周围的符号分开。我不喜欢使用$(set -o | grep xtrace)
;与使用$-
相比,这是非常沉重的。你可以再次使用$-
来解决这个问题:
alias debug='[[ ! $- =~ x ]] && { set -o nounset -o xtrace; echo "Debug mode ON"; } || { set +o nounset +o xtrace; echo "Debug mode OFF"; }'
打开调试时有点吵;它最好写成:
alias debug='[[ ! $- =~ x ]] && { echo "Debug mode ON"; set -o nounset -o xtrace; } || { set +o nounset +o xtrace; echo "Debug mode OFF"; }'
在跟踪关闭时完成echo
。当调试当前处于打开状态并且您即将关闭时,您仍然可以看到测试结果。这是不可避免的。
您还可以使用明确的if
/ then
/ else
/ fi
:
alias debug='if [[ $- =~ x ]]; then set +o nounset +o xtrace; echo "Debug mode OFF"; else echo "Debug mode ON"; set -o nounset -o xtrace; fi'
或者压缩到:
alias debug='if [[ $- =~ x ]]; then set +xu; echo "Debug mode OFF"; else echo "Debug mode ON"; set -xu; fi'
答案 1 :(得分:1)
alias debug="[[ \$(set -o | grep xtrace) = *off ]] && { set -o nounset; set -o xtrace; echo 'Debug mode ON'; } || { set +o nounset; set +o xtrace; echo 'Debug mode OFF'; }"
{ }
可以将多个命令组合在一起,而无需像()
那样创建子shell。语法有点不同;你需要确保在{ }
和任何单词之间留下空格,否则它可以被解释为{a,b} → a b
大括号扩展,并且命令需要以;
(或{{ 1}})。