![使用 `$1` 和后备默认值的别名会打印参数和后备值](https://linux22.com/image/182725/%E4%BD%BF%E7%94%A8%20%60%241%60%20%E5%92%8C%E5%90%8E%E5%A4%87%E9%BB%98%E8%AE%A4%E5%80%BC%E7%9A%84%E5%88%AB%E5%90%8D%E4%BC%9A%E6%89%93%E5%8D%B0%E5%8F%82%E6%95%B0%E5%92%8C%E5%90%8E%E5%A4%87%E5%80%BC.png)
我想创建一个可以处理参数 ( $1
) 的别名,并且如果未提供参数,则可以回退到默认值。例如,
$ alias foo='NUM=${1:-42}; echo $NUM'
不带参数调用它可以按我想要的方式工作:
$ foo
42
但使用参数调用时,它会打印我的值和默认值:
$ foo 69
42 69
我不明白为什么会这样。应该如何正确进行呢?我该如何自己调试此类问题?
答案1
别名只是另一轮 shell 语法解释之前的文本替换,它们不接受参数,因此之后:
foo 69
文本foo
被替换为NUM=${1:-42}; echo $NUM
,然后 shell 解释生成的文本:
NUM=${1:-42}; echo $NUM 69
$1
还没有设置,所以那就是NUM=42; echo 42 69
对于在当前 shell 中解释并带有参数的内联脚本,请使用功能反而:
foo() {
NUM=${1-42}
printf '%s\n' "$NUM"
}
这里使用${1-42}
而不是${1:-42}
,就像用户调用一样foo ''
,我假设他们希望$NUM
被分配空字符串。
答案2
我该如何自己调试此类问题?
一个标准的调查步骤是深入了解到底发生了什么:
$ alias foo='NUM=${1:-42}; echo $NUM'
$ foo 69
42 69
$ echo "$NUM"
42
即使您已将别名定义为 echo $NUM
,您也应该自己手动执行此操作。上面显示NUM
设置为 42。这可能会给您一个线索,即别名的“69”参数 foo
没有与分配交互 NUM=
; (显而易见?)的结论是它仅影响 echo
.
一些一般性的建议是避免echo
支持 printf
.
echo
如果第一个参数以连字符 ('-
'),即使它来自变量:
当然,您还应该引用变量。$ NUM="In a perfect world..." $ echo $NUM; echo ABC In a perfect world... ABC $ NUM="-n a perfect world..." $ echo $NUM; echo ABC a perfect world...ABC
echo
如果参数包含反斜杠,则会产生奇怪的效果。
printf
还可以处理反斜杠,但是……- ... 的行为
printf
是标准化的,但大约有 42 个不同的版本echo
。 - 对于这个练习来说最重要的是,
echo
没有阐明争论之间的界限。echo Super User
并echo "Super User"
产生相同的输出。
所以试试这个:
$ alias foop='NUM=${1:-42}; printf "[%s]\n" $NUM'
$ foop
[42]
$ foop 69
[42]
[69]
$ foop The quick brown fox
[42]
[The]
[quick]
[brown]
[fox]
这应该非常清楚地表明您的参数被应用于别名的末尾,并且不会与赋值纠缠在一起。另外,别名的代码不仅仅查看第一个参数。
既然您了解您无法控制别名的$1
,您可能想知道 的值NUM
来自哪里。我不知道在你完全诊断出问题之前期望你考虑这个是否合理,但是
$ set Once upon a midnight dreary
$ foo
Once
$ echo "$NUM"
Once
应该澄清这样一个事实:$1
别名定义中的 是查看 shell 的现有参数列表,而不是传递给别名调用的参数。
答案3
在别名中使用函数:
$ alias foo='function foo { NUM=${1:-42}; echo $NUM; }; foo'
$ foo
42
$ foo 69
69