따옴표 붙은 변수가 비어 있으면 어떻게 확장 할 수 있습니까? : some-command ” “$var2” … 변수를 테스트하고 조건부로

내가 스크립트를하고 있다고 가정 해보십시오.

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 등에서 아무것도 확장 할 수없는 것보다 매개 변수 대체가 있습니까? 여전히 나머지 인수에서 globbing을 사용하고 싶을 수 있으므로 해당 변수를 비활성화하고 변수를 인용 해제하는 것은 옵션이 아닙니다.



답변

Posix 호환 쉘Bash에는 ${parameter:+word} 다음 이 있습니다 .

경우 파라미터가 해제 또는 널, 널 치환한다; 그렇지 않으면 단어 의 확장 (또는 단어 가 생략 된 경우 빈 문자열 )이 대체됩니다.

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

${var1:+"$var1"}

그리고 한 var1확인하고, "$var1"이 설정하고 비 비어있는 경우 (보통 이중 인용 규칙) 사용. 그렇지 않으면 아무것도 확장되지 않습니다. 전체 내용이 아니라 내부 부분 만 인용합니다.

zsh에서도 마찬가지입니다. 변수를 반복해야하므로 이상적이지는 않지만 원하는대로 정확하게 작동합니다.

빈 값으로 설정된 변수를 빈 인수로 확장하려면 ${var1+"$var1"}대신 사용하십시오.


답변

그게 무슨 zsh당신이 따옴표를 생략 할 때 기본적으로 수행합니다

some-command $var1 $var2

실제로 zsh에서 매개 변수 확장과 관련하여 여전히 따옴표가 필요한 유일한 이유는 매개 변수 확장을 인용하지 않을 때 다른 쉘에 영향을 미치는 다른 문제zsh 가 없기 때문에 해당 동작 (빈 제거)을 피하기위한 것입니다 (암시 적 분할 + 글로브) .

split과 glob를 비활성화하면 다른 POSIX와 같은 셸에서 동일한 작업을 수행 할 수 있습니다.

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

이제 변수에 0 또는 1 값을 가질 수 있다면 스칼라 변수가 아닌 배열이어야하며 다음을 사용하십시오.

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

그리고 var1=(value)when var1은 하나의 값 var1=('')을 포함하고, 하나의 빈 값 var1=()을 포함하고 , 값 을 포함 하지 않을 때 사용합니다 .


답변

-n드라이 런을 토글 하거나 토글 하지 않고 명령을 시작한 bash 스크립트에서 rsync를 사용 하여이 문제에 부딪 쳤습니다 . rsync 및 많은 gnu 명령 ''은 유효한 첫 번째 인수로 사용되며 존재하지 않는 경우와 다르게 작동합니다.

널 (null) 매개 변수가 거의 완전히 보이지 않기 때문에 디버그하는 데 꽤 시간이 걸렸습니다.

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[@]}" ...