ZSH에서 공백이 포함된 환경 변수를 올바르게 내보내는 방법

ZSH에서 공백이 포함된 환경 변수를 올바르게 내보내는 방법

공백이 포함된 환경 변수를 추가합니다.~/.zshrc

export SKIP="-Dskip1 -Dskip2"
export SKIP_NO_SPACES="-Dskip3"

사용해 보세요

set -x  
mvn $SKIP $SKIP_NO_SPACES

실행되는 명령은 실제로

+-zsh:108> mvn '-Dskip1 -Dskip2' -Dskip3

공백이 포함된 변수만 인용됩니다.

작은따옴표가 추가되는 것을 방지하는 방법은 무엇입니까?

인용/이스케이프를 전혀 사용하지 않으면 셸을 열 때 오류가 발생합니다.

/.zshrc:export:11: 이 컨텍스트에서는 유효하지 않습니다: -Dskip2

답변1

내 생각에 당신은 여기서 환경 변수를 남용하고 있는 것 같습니다. 해당 공백은 변수의 일부이며 를 사용하여 매개변수 확장을 수행하면 $해당 공백이 명령에 전달됩니다. mvn변수 내용이라는 하나의 인수를 얻습니다.

Kamil Maciorowski가 주석에서 올바르게 관찰했듯이 이는 Zsh에만 해당됩니다. 따옴표를 생략하면 제안한 내용이 Bash에서 작동합니다.

bash-5.0$ export test="foo bar"
bash-5.0$ ls $test
ls: bar: No such file or directory
ls: foo: No such file or directory
bash-5.0$ ls "$test"
ls: foo bar: No such file or directory

원하는 것을 수행하는 한 가지 대안은전역 별칭(Bash가 아닌 Zsh의 기능이기도 함) 이는 한 줄의 어느 곳에서나 대체될 수 있습니다. 공백을 유지합니다.

$ alias -g SKIP="-Dskip1 -Dskip2"
$ alias -g SKIP2="-Dskip3"
$ mvn SKIP SKIP2

이렇게 하면 문자열이 추가될 때마다 "추가"됩니다.

답변2

문제는 인용이나 이스케이프와는 아무 관련이 없으며 모두 단어 분할(또는 분할 부족)과 관련이 있습니다. 대부분의 셸에서 공백이 포함된 변수를 큰따옴표로 묶지 않고 사용하면 해당 공백을 기준으로 값이 "단어"로 분할됩니다. 따라서 변수가 SKIP로 설정되어 있고 -Dskip1 -Dskip2(이 값에는 따옴표나 이스케이프가 없음에 유의) 처럼 사용하면 mvn $SKIP와 동일해집니다 mvn "-Dskip1" "-Dskip2".

그러나 zsh는 대부분의 쉘이 아니며 (기본적으로) 단어 분할을 수행하지 않습니다. 변수가 로 설정된 경우 -Dskip1 -Dskip2해당 내용이 명령에 전달됩니다.단일 인수로. 출력 에 표시되는 따옴표는 set -x실제로 존재하지 않으며 전체 문자열이 단일 인수로 전달된다는 것을 명시적으로 나타내기 위해 추가되었을 뿐입니다.

단어 분할이 완료되기를 원한다고 zsh에 알리는 몇 가지 방법이 있습니다. =확장에서 수정자를 사용할 수 있습니다 .

mvn ${=SKIP}

또는 쉘 옵션을 사용하여 모든 확장에 대해 sh와 같은 분할을 설정할 수 있습니다.

setopt shwordsplit
mvn $SKIP

...그러나 이는 단일 인수라고 생각했던 것들이 예기치 않게 분할되거나 파일 이름 와일드카드처럼 보이는 모든 것이 파일 이름 목록으로 확장되는 등 불쾌한 부작용을 초래할 수 있습니다. 쉘 단어 분할은 버그를 일으키는 경향이 있으므로 zsh에서는 기본적으로 비활성화되어 있습니다. 여러 문자열을 변수에 저장하는 가장 적절한 방법은 일반 변수 대신 배열을 사용하는 것입니다.

SKIP=(-Dskip1 -Dskip2)
mvn "${SKIP[@]}"

이는 zsh, bash 및 기타 일부 셸에서 작동합니다(그러나 배열 지원이 없는 셸에서는 작동하지 않음). 그러나 zsh에서 배열을 내보낼 수는 없습니다. 를 실행할 수는 있지만 export SKIP아무 작업도 수행하지 않습니다. 배열은 셸 기능인 반면 환경 변수는 일반 문자열만 지원하는 OS입니다. 이러한 옵션을 실제로 내보내야 합니까, 아니면 셸 내에서 사용하고 있습니까?

답변3

로 인해 인쇄된 진단 줄에 작은따옴표가 나타납니다 set -x. 그들은 mvn. 변수 내용( )은 변수를 엄격하게 인용할 필요가 없기 때문에 단일 인수로 -Dskip1 -Dskip2사용됩니다 (POSIX 호환 쉘에서는 인용).mvnzsh

문제는 변수를 확장하는 방식에 있는 것 같습니다 zsh. 따옴표가 없을 때 단어 분할이 발생하기를 원한다고 생각합니다 $SKIP(다른 껍질에서 일어나는 것처럼) 그러나 zsh일반적으로 발생하지 않습니다.

사용 ${=SKIP}대상대체 후 단어 분할 트리거.

예:

% SKIP='-Dskip1 -Dskip2' 
% printf "%s\n" $SKIP   
-Dskip1 -Dskip2
% printf "%s\n" ${=SKIP}
-Dskip1
-Dskip2
% 

관련 정보