如何有条件地从 POSIX shell 脚本传递参数?

如何有条件地从 POSIX shell 脚本传递参数?
#!/bin/sh
echo "Noise $1"
echo "Enhancement $2"
for snr in 0 5 10 15 20 25
do
  python evaluate.py --noise $1 --snr 25 --iterations 1250 --enhancement $2
done

如果$2未指定,我不想将参数传递--enhancement $2给我的 python 脚本。我该怎么做呢?

答案1

修改原来的脚本:

#!/bin/sh
echo "Noise $1"
echo "Enhancement $2"
for snr in 0 5 10 15 20 25
do
  python evaluate.py --noise "$1" --snr "$snr" --iterations 1250 ${2:+--enhancement "$2"}
done

标准参数扩展 ${var:+word}word如果变量var已设置且不为空,则将扩展为。在上面的代码中,我们使用它来添加--enhancement "$2"到命令(如果$2可用且不为空)。

我还冒昧地假设您--snr作为选项参数提供的应该是循环变量的值。


我个人对代码的看法(主要是使用printf而不是echo,避免长行,并给代码更多的空气):

#!/bin/sh

printf 'Noise %s\n' "$1"
printf 'Enhancement %s\n' "$2"

for snr in 0 5 10 15 20 25; do
    python evaluate.py \
        --noise "$1" \
        --snr "$snr" \
        --iterations 1250 \
        ${2:+--enhancement "$2"}
done

正如 mosvy 在下面的评论中指出的那样:如果您/bin/sh碰巧是shell,或其他一些 shell在新的 shell 会话启动时dash无法正确重置(这是 POSIX 所要求的),并且如果您出于某种原因,IFS导出IFS并给它一个非默认值,那么您可能需要unset IFS在上面脚本的顶部使用。

每当你修好后就这样做IFS出口无疑引起的所有其他问题(不要导出IFS)。

答案2

在不支持任何数组的最小 POSIX shell 上,您只需使用set命令操作位置参数列表即可。在循环之前for你可以做

if [ -z "$2" ]; then
    set -- --noise "$1" --snr 25 --iterations 1250
else
    set -- --noise "$1" --snr 25 --iterations 1250 --enhancement "$2"
fi

现在运行你的 for 循环

for snr in 0 5 10 15 20 25; do
    python evaluate.py "$@"
done

如果您的 shell 支持数组 bourne Again shellbashzsh其他,您可以只使用数组

argv=(--noise "$1" --snr 25 --iterations 1250)

if [ ! -z "$2" ]; then
    argv+=( --enhancement "$2" )
fi

现在将脚本称为

python evaluate.py "${argv[@]}"

正如评论中指出的,你是不是snr使用for 循环中 value的实际值。使用脚本参数中适用的值$snr,在这种情况下,您可能需要在循环内移动构造参数列表的逻辑。

答案3

您可以使用命令替换在一行中完成此操作

  python evaluate.py --noise $1 --snr 25 --iterations 1250 $(test -n "$2" && echo --enhancement "$2")

答案4

使变量扩展消失的唯一方法是在扩展未加引号时将扩展扩展为空值。

$ unset a; b=''; c=set
$ printf '<%s> ' unquoted $a $b quoted "$a" "$b" val $c "$c"; echo
<unquoted> <quoted> <> <> <val> <s> <t> <set>

当不加引号时,变量的未设置值和空值(ab)都会消失(作为参数)。引用时两者均被保留。

此外,如果包含在 IFS 中,甚至空格(或任何字符)也会消失。

$ IFS=' '
$ unset a; b=' '; c='  set  '
$ printf '<%s> ' unquoted $a $b quoted "$a" "$b" val $c "$c"; echo
<unquoted> <quoted> <> < > <val> <set> <  set  >

事实上,在要扩展的值中包含字符(不带引号)的 IFS 将分隔参数。

$ IFS='e '
$ $ printf '<%s> ' unquoted $a $b quoted "$a" "$b" val $c "$c"; echo
<unquoted> <quoted> <> < > <val> <s> <t> <  set  >

请注意两个参数<s>和 ,它们是在 IFS 包含 时<t>扩展值而产生的。sete

因此,我们需要对未设置或空值进行无引号扩展,当有值要扩展时,它会成为该值的带引号扩展:

${var:+"$var"}

描述:

${             # starts an un-quoted variable expansion
  var          # name of variable to expand
     :         # also replace if var is null
      +        # use what follows if is not unset (nor null)
       "$var"  # a quoted variable expansion.
             } # end of expansion.

# In short: expand "$var" if it has a value, $var otherwise.

然后我们可以利用$1价值来消除它或扩大它

echo ${1:+"--noise"} ${1:+"$1"}

上面的行将打印$1如果有一些(非空)值,则单独的参数(不受 IFS 影响);如果$1为空或未设置,则没有任何值。

该脚本将变为:

#!/bin/sh
echo "Noise $1"
echo "Enhancement $2"

for    snr in 0 5 10 15 20 25
do     python evaluate.py \
         ${1:+"--noise"} ${1:+"$1"} \
         --snr "$snr" \
         --iterations 1250 \
         ${2:+"--enhancement"} ${2:+"$2"}
done

该方案不受IFS值的影响

相关内容