참조된 변수가 null인 경우 어떻게 null로 확장할 수 있나요?

참조된 변수가 null인 경우 어떻게 null로 확장할 수 있나요?

실행 중인 스크립트가 있다고 가정해 보겠습니다.

some-command "$var1" "$var2" ...

비어 있으면 var1빈 문자열보다는 빈 문자열로 대체하여 실행되는 명령이 다음과 같도록 합니다.

some-command "$var2" ...

아니다:

some-command '' "$var2" ...

변수를 테스트하고 조건부로 포함시키는 것보다 더 쉬운 방법이 있습니까?

if [ -n "$1" ]; then
    some-command "$var1" "$var2" ...
    # or some variant using arrays to build the command
    # args+=("$var1")
else
    some-command "$var2" ...
fi

bash, zsh 등에서 null로 확장되는 매개변수 대체가 있습니까? 여전히 나머지 매개변수에 와일드카드를 사용하고 싶을 수도 있으므로 이를 비활성화하고 변수를 역참조하는 것은 옵션이 아닙니다.

답변1

Posix 호환 쉘그리고큰 타격을 입었습니다 ${parameter:+word}:

만약에범위설정되지 않았거나 null입니다. 그렇지 않으면 null로 바꿔야 합니다.단어(또는 빈 문자열인 경우단어생략)을 교체해야 합니다.

그래서 당신은 이것을 할 수 있습니다 :

${var1:+"$var1"}

설정되어 있고 비어 있지 않으면 var1확인되어 사용 됩니다 (일반적인 큰따옴표 규칙 사용). "$var1"그렇지 않으면 아무것도 부풀어오르지 않을 것입니다. 참고하시기 바랍니다내부에여기에 인용된 내용은 전체가 아닌 일부입니다.

zsh에서도 작동합니다. 변수를 반복해야 하므로 이상적이지는 않지만 정확히 원하는 결과가 나옵니다.

set-but-empty 변수를 빈 매개변수로 확장하려면 대신 set-but-empty를 사용하십시오 ${var1+"$var1"}.

답변2

zsh따옴표를 생략하면 기본적으로 다음과 같은 일이 발생합니다.

some-command $var1 $var2

실제로 zsh의 매개변수 확장에 인용문이 여전히 필요한 유일한 이유는 이 동작(null 삭제)을 피하기 위한 것입니다 zsh.매개변수 확장을 인용하지 않을 때 다른 쉘에 영향을 미치는 기타 문제(암시적 분할+glob).

분할 및 glob이 비활성화된 경우 다른 POSIX 유사 셸에서도 동일한 작업을 수행할 수 있습니다.

(IFS=; set -o noglob; some-command $var1 $var2)

이제 변수가 0 또는 1의 값을 가질 수 있다면 스칼라 변수 대신 배열이어야 하며 다음을 사용해야 한다고 생각합니다.

some-command "${var1[@]}" "${var2[@]}"

값을 포함할 var1=(value)때 , null 값을 포함할 때, 포함할 때를 사용합니다.var1var1=('')var1=()아니요값.

답변3

-n스위치 드라이 런 유무에 관계없이 명령을 실행하는 bash 스크립트에서 rsync를 사용하여 이 문제가 발생했습니다. rsync와 많은 gnu 명령은 이를 ''유효한 첫 번째 인수로 받아들이고 존재하지 않을 때와 다르게 동작하는 것으로 나타났습니다 .

빈 매개변수가 거의 완전히 보이지 않기 때문에 디버깅하는 데 꽤 오랜 시간이 걸렸습니다.

rsync 목록에 있는 누군가가 나에게 이 문제를 피하는 방법을 보여줬습니다.매우코딩을 단순화하세요. 내가 올바르게 이해했다면 이것은 @Stéphane Chazelas가 마지막으로 제안한 변형입니다.

많은 개별 변수에 명령 인수를 구성합니다. 이는 문제에 적합한 순서나 논리로 설정할 수 있습니다.

그런 다음 마지막에 변수를 사용하여 모든 것이 제자리에 있는 배열을 구성하고 이를 실제 명령에 대한 인수로 사용합니다.

이런 방식으로 명령은 매개변수의 각 변형에 대해 반복되지 않고 코드의 한 위치에서만 실행됩니다.

이 방법을 사용하면 빈 변수가 모두 사라집니다.

나는 eval을 사용하는 것이 눈살을 찌푸리는 일이라는 것을 알고 있습니다. 모든 세부 사항을 기억하지는 못하지만 이런 식으로 작업하려면 공백이 포함된 매개 변수를 처리하는 것과 관련하여 작업이 필요한 것 같습니다.

예:

dry_run=''
if [[ it is a test run ]]
then
  dry_run='-n'
fi
...
rsync_options=(
  ${dry_run}
  -avushi
  ${delete}
  ${excludes}
  --stats
  --progress
)
...
eval rsync "${rsync_options[@]}" ...

관련 정보