web-dev-qa-db-ja.com

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

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

17
Shamoon

元のスクリプトを変更します。

#!/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/shdashシェル、または新しいシェルセッションの開始時にIFSを適切にリセットしない他のシェルである場合(これはPOSIXで必要です)、何らかの理由でIFSをエクスポートし、それにデフォルト以外の値を指定した場合は、上記の上部でunset IFSを使用することができます。脚本。

修正したときはいつでも_IFSをエクスポートする他のすべての問題が疑いなく発生しました(_IFSをエクスポートしないでください) 。

30
Kusalananda

配列をサポートしない最小限の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

シェルが配列ボーンを再度サポートしている場合は、シェルbashzshまたはその他の場合、配列を使用できます

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

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

スクリプトを次のように呼び出します

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

コメントで指摘されているように、あなたはnot forループからのsnr値の実際の値を使用しています。スクリプト引数の該当する場合は、値を$snrとして使用します。この場合、引数リストを作成するロジックをループ内に移動する必要がある場合があります。

12
Inian

入力に基づいて変数に引数を作成します。

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

if [ $# -eq 1 ]
then
   enhance=""
else
   enhance="--enhancement $2"
fi

for snr in 0 5 10 15 20 25
do
  python evaluate.py --noise $1 --snr "$snr" --iterations 1250 $enhance
done

(ループ本体のループ変数の修正も含まれます)

2

コマンド置換を使用して、1行で実行できます。

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

変数展開を非表示にする唯一の方法は、展開が引用符で囲まれていないときに展開を空の値に展開させることです。

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

変数(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  >

IFSにsetが含まれている場合に値eを拡張した結果として生じた2つの引数<s>および<t>に注意してください。

したがって、展開する値がある場合に、値の引用符で囲まれた展開になる、未設定または空の値の引用符で囲まれていない展開が必要です。

${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ではない)値がある場合はtwo個別の引数(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の価値の影響を受けません

0
Isaac