따옴표 붙은 변수가 비어 있으면 어떻게 확장 할 수 있습니까?


21

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

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을 사용하고 싶을 수 있으므로 해당 변수를 비활성화하고 변수를 인용 해제하는 것은 옵션이 아닙니다.


나는 전에 이것을 보았고 아마 이것을 사용했다는 것을 알았지 만 찾기가 어려웠습니다. 이제 Michael이 구문을 보여 주었 으므로 , 내가 처음으로 충분히 빨리 본 곳을 기억했습니다 : unix.stackexchange.com/a/269549/70524 , unix.stackexchange.com/q/68484/70524
muru

그것이 어떤 종류의 매개 변수 대체라는 것을 알고 있다면 왜 페이지 의 매개 변수 확장 섹션을 보지 않았 man습니까? (-;
Philippos

1
@Philippos 나는 당시에 그것이 무엇인지 몰랐습니다. 알려진 알려진 및 알려지지 않은 알려진. :(
muru

1
질문 자체의 인수를 보유하기 위해 배열을 사용한다고 언급하기위한 추가 쿠키 포인트.
ilkkachu

답변:


29

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

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

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

${var1:+"$var1"}

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

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

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


1
나를 위해 충분합니다. 따라서 이것에서 모든 것은 인용되지 않았으며 word일부만 인용되었습니다 .
muru

1
질문에 "bash, zsh 등"(및 Q & A 아카이브)이 요청됨에 따라 이것이 posix 기능임을 반영하도록 편집되었습니다. 심지어 내 의견 후에 질문에 / bash 태그를 추가하면. (-;
Philippos

2
나는 사이의 차이에서 편집의 자유 갔다 :++.
ilkkachu

POSIX 호환 솔루션에 감사드립니다! 나는 잠재적 인 chokepoint 스크립트에 sh/ 를 사용하려고 dash하므로 Bash에 의존하지 않고 어떻게 가능한지 보여줄 때 항상 감사합니다.
JamesTheAwesomeDude

나는 반대 효과를 찾고있었습니다 (null로 시작하면 다른 것으로 확장). $ {empty_var : -replacement}
Alex Jansen

5

그게 무슨 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=()을 포함하고 , 값 을 포함 하지 않을 때 사용합니다 .


0

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

그것은 질문에서 설명한 것을 수행하는 더 나쁜 방법입니다 (조건부로 인수 배열 만들기). 변수를 인용 부호로 남겨두면 누가 어떤 문제에 직면했는지 알 수 있습니다.
muru

@muru 당신 말이 맞지만, 여전히 이런 것이 필요합니다. 다른 답변의 기술을 사용하여 문제를 해결하는 방법을 잘 모르겠습니다. 코드 조각이 올바른 방법으로 수행되는 것을 보는 것이 좋습니다. 나중에 Stephane의 마지막 옵션을 사용하여 원하는 것을 할 수 있습니다.
Joe


방금 이것으로 돌아 왔습니다. 예를 주셔서 감사합니다. 말된다. 나는 그것을 사용할 것입니다.
Joe

비슷한 사용 사례가 있지만 다음과 같이 할 수 있습니다. if [ "$ dry"== "true"]; 그런 다음 dry = "-n"; fi ... 따라서 변수 dry가 true이면 -n으로 설정 한 다음 평소와 같이 rsync 명령을 작성하고 다음과 같이합니다. rsync $ {dry1 : + "$ dry1"} ... null 인 경우 아무 일도 일어나지 않을 것입니다. 그렇지 않으면 명령에 -n이됩니다
Freedo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.