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

명령 대체를 사용하여 한 줄로 이 작업을 수행할 수 있습니다.

  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가 포함될 때 값을 확장한 결과인 두 개의 매개변수 및 에 유의하십시오 <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 값의 영향을 받지 않습니다.

관련 정보