使用 `$1` 和后备默认值的别名会打印参数和后备值

使用 `$1` 和后备默认值的别名会打印参数和后备值

我想创建一个可以处理参数 ( $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.

  1. 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
    
    当然,您还应该引用变量。
  2. echo如果参数包含反斜杠,则会产生奇怪的效果。
    printf还可以处理反斜杠,但是……
  3. ... 的行为printf是标准化的,但大约有 42 个不同的版本 echo
  4. 对于这个练习来说最重要的是, echo没有阐明争论之间的界限。  echo Super Userecho "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

相关内容