简体   繁体   English

程序参数中带有参数扩展的奇怪行为

[英]Strange behavior with parameter expansion in program arguments

I'm trying to conditionally pass an argument to a bash script only if it has been set in the calling script and I've noticed some odd behavior. 我试图仅在调用脚本中设置了参数的情况下才将参数传递给bash脚本,并且我注意到某些奇怪的行为。 I'm using parameter expansion to facilitate this, outputting an option only if the corresponding variable is set. 我正在使用参数扩展来简化此操作,仅在设置了相应变量的情况下才输出选项。 The aim is to pass an argument from a 'parent' script to a 'child' script. 目的是将参数从“父”脚本传递到“子”脚本。

Consider the following example: 考虑以下示例:

The calling script: 调用脚本:

#!/bin/bash
# 1.sh

ONE="TEST_ONE"
TWO="TEST_TWO"

./2.sh \
    --one "${ONE}" \
    "${TWO:+"--two ${TWO}"}" \
    --other

and the called script: 和被调用的脚本:

#!/bin/bash
# 2.sh

while [[ $# -gt 0 ]]; do
    key="${1}"

    case $key in
        -o|--one)
        ONE="${2}"
        echo "ONE: ${ONE}"
        shift
        shift
        ;;
        -t|--two)
        TWO="${2}"
        echo "TWO: ${TWO}"
        shift
        shift
        ;;
        -f|--other)
        OTHER=1
        echo "OTHER: ${OTHER}"
        shift
        ;;
        *)
        echo "UNRECOGNISED: ${1}"
        shift
        ;;
    esac
done

output: 输出:

ONE: TEST_ONE
UNRECOGNISED: --two TEST_TWO
OTHER: 1

Observe the behavior of the option '--two', which will be unrecognised. 观察选项“ --two”的行为,该行为不会被识别。 It looks like it is being expanded correctly, but is not recognised as being two distinct strings. 看起来好像已正确扩展了该字符串,但并未将其识别为两个不同的字符串。 Can anyone explain why this is happening? 谁能解释为什么会这样? I've seen it written in one source that it will not work with positional parameter arguments , but I'm still not understanding why this behaves as it does. 我已经看到它是在一个来源中编写的, it will not work with positional parameter arguments ,但是我仍然不明白为什么这样做会如此。

It is because when you pass $2 as a result of parameter expansion from 1.sh you are quoting it in a way that --two TEST_TWO is evaluated as one single argument, so that the number of arguments in 2.sh result in 4 instead of 5 这是因为当您从$2 1.sh进行参数扩展时传递$2时,您以--two TEST_TWO作为一个单一参数求值的方式1.sh进行引用,从而使2.sh中的参数数改为45

But that said, using your $2 as ${TWO:+--two ${TWO}} would solve the problem, but that would word-split the content of $2 if it contains spaces. 但这就是说,将您的$2用作${TWO:+--two ${TWO}}可以解决此问题,但是如果$2包含空格,则会将其单词拆分。 You need to use arrays. 您需要使用数组。

As a much more recommended and fail-proof approach use arrays as below on 1.sh as 作为一种更推荐1.sh方法,请在1.sh上使用以下数组:

argsList=(--one "${ONE}" ${TWO:+--two "${TWO}"} --other)

and pass it along as 并将其作为

./2.sh "${argsList[@]}"

or if you are familiar with how quoting rules work (how and when to quote to prevent word-splitting from happening) use it directly on the command line as below. 或者,如果您熟悉引用规则的工作原理(如何以及何时引用以防止单词拆分的发生),请在命令行上直接使用它,如下所示。 This would ensure that the contents variables ONE and TWO are preserved even if they have spaces. 这样可以确保内容变量ONETWO即使有空格也可以保留。

./2.sh \
    --one "${ONE}" \
    ${TWO:+--two "${TWO}"} \
    --other

As a few recommended guidelines 作为一些推荐的准则

  • Always use lower-case variable names for user defined variables to not confuse them with the environment variables maintained by the shell itself. 始终对用户定义的变量使用小写的变量名,以免将它们与外壳程序本身维护的环境变量混淆。
  • Use getopts() for more robust argument flags parsing 使用getopts()进行更健壮的参数标志解析

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM