POSIXシェルスクリプトで条件付きでパラメータを渡す方法は?

POSIXシェルスクリプトで条件付きでパラメータを渡す方法は?
#!/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

指定しない場合は、Pythonスクリプトに$2引数を渡したくありません。--enhancement $2どうすればいいですか?

答え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シェルの場合、または新しいシェルセッションの開始時に他のシェルが正しくリセットされない場合dash(POSIXで必要)、何らかの理由でエクスポートしてIFS提供IFSしてください。デフォルト以外の値の場合は、上記のスクリプトのunset IFS一番上で使用できます。

修正するたびにこれを行うIFS輸出によって疑われる余地なく提起されるその他の問題(エクスポートしないでくださいIFS)。

答え2

配列をサポートしない最小POSIXシェルでは、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

シェルが bourne Again シェルbashまたはzsh他の配列をサポートしている場合は、配列を使用できます。

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

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

それではスクリプトを呼び出してください。

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

コメントで指摘したように、あなたはいいえsnrforループでvalueの実際の値を使用します。スクリプトパラメータで適用可能な値を使用してください$snr。この場合、ループ内でパラメータリストを設定するためにロジックを移動する必要があるかもしれません。

答え3

コマンド置換を使用して、1行でこれを行うことができます。

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

答え4

変数拡張を排除する唯一の方法は、引用符なしで拡張するときにnullに拡張することです。

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

引用符をオフにすると、変数の未設定値とnull値(aおよび)が(引数として)消えます。b引用は両方とも維持されます。

さらに、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が含まれているときに値を拡張した結果である2つのパラメーターに注意してください<t>sete

したがって、設定されていない値またはNULL値を引用符で囲まれていない拡張が必要です。拡張する値がある場合は、その値を引用符で囲んだ拡張になります。

${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いくつかの値(null以外)がある場合は、別のパラメータ(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値の影響を受けません。

関連情報