환경 변수를 사용하여 zsh에 플래그를 저장하는 방법은 무엇입니까?

환경 변수를 사용하여 zsh에 플래그를 저장하는 방법은 무엇입니까?

나는 함께 일하고 있다쿠벡텔그리고 zsh에서는 네임스페이스 플래그를 환경 변수에 저장하고 싶습니다.

다음을 작성하는 대신:

kubectl get pods -n mynamespace

나는 이런 일을하고 싶다 :

n='-n mynamespace'
kubectl get pods $n

하지만 이렇게 하면 다음과 같은 결과를 얻습니다.

No resources found in  mynamespace namespace.

in단어와 사이에 공백이 두 개 있다는 점 에 유의하세요 mynamespace.

을 실행하면 kubectl get pods -n mynamespace올바른 출력을 얻습니다.

NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          16m

여기서 무슨 일이 일어나는가? in단어와 출력 사이에 공백이 두 개 있는 이유는 무엇 입니까 mynamespace? 환경 변수에 네임스페이스 플래그를 저장하는 방법은 무엇입니까?

답변1

zsh는 변수에 대해 토큰화를 수행하지 않지만 해당 값을 단일 인수로 전달합니다. 여기에는 kubectl이 없지만 mkdir과 ​​같은 항목을 사용하여 동작을 재현할 수 있습니다.

var='-p a/b/c/d'
comp% mkdir $var
mkdir: invalid option -- ' '
Try 'mkdir --help' for more information.

다음을 사용하여 동일한 오류를 호출할 수 있습니다.

comp% mkdir '-p a/b/'
mkdir: invalid option -- ' '
Try 'mkdir --help' for more information.

zsh가 실제로 무엇을 하고 있는지 볼 수 있습니다 strace -f mkdir $var:

execve("/usr/bin/mkdir", ["mkdir", "-p a/b/c/d"], 0x7ffce5e6afb0 /* 61 vars */) = 0

제안을 따르세요이 답변에서 예를 들어, 단어 분할을 활성화해야 합니다.

comp% mkdir -p ${=var}

귀하의 경우에는 다음과 같습니다:

kubectl get pods ${=n}

답변2

쉘 변수(또는 모든 언어의 변수)를 다음과 결합하지 마십시오.환경바꾸다. 환경 변수는 var=value명령을 실행할 때 매개변수 배열과 함께 명령에 전달되는 구문의 문자열 배열입니다 . 명령줄 인수와 마찬가지로 한 명령에서 관련되지 않은 다른 명령으로 문자열을 전달하는 데 사용됩니다.

쉘에는 일부 스칼라 변수를 시작 시 수신된 일부 환경 변수에 매핑하는 특징이 있습니다(이 변수의 이름은 유효한 쉘 변수 이름이며 특수 쉘 변수와 충돌하지 않습니다). 반면 다른 언어에서는 getenv()이를 검색하기 위해 다음과 같은 것을 사용합니다( 또는 ENVIRONof awk또는 perl 과 같은 특수 연관 배열에 매핑 %ENV하지만 이것이 쉘이 자체 변수를 가질 수 없거나 스칼라 변수로 제한되지 않는다는 의미는 아닙니다.

하나의 변수에 여러 값을 저장하고 싶다면 배열/목록 변수를 사용하면 됩니다. zsh는 1991년(bash 이전) 버전 2.0부터 배열을 지원해 왔으며 실제로 array=(foo bar)이를 선언하는 구문을 도입한 것은 셸이었습니다( set array=(foo bar)70년대 후반의 csh와 유사). 이제 ksh93, bash, mksh 및 yash에서도 지원됩니다. .

에서는 zsh다음을 수행합니다.

options=(-n mynamespace)
kubectl get pods $options

에서는 yash다음을 수행합니다.

options=(-n mynamespace)
kubectl get pods "$options"

그리고 ksh93/bash에서는(zsh도 이를 지원하며 빈 요소를 버리지 않는다는 장점도 있습니다 yash.)

options=(-n mynamespace)
kubectl get pods "${options[@]}"

이제 배열은 환경 변수로 내보낼 수 없으며 NUL이 아닌 바이트의 일반 문자열일 뿐입니다.

만약 이 과정을 통과해야 한다면kubectl논쟁으로하나환경 변수를 사용하려면 어떤 형태로든 인코딩을 사용하여 문자열 배열에서 문자열을 가져온 다음 이를 분할하여 두 매개변수를 가져와야 합니다 kubectl.

대략적인 인코딩으로 공백과 연결하도록 선택합니다. 이는 각 요소에 공백이 포함될 수 없음을 의미합니다.

임의의 구분 기호로 단어를 연결하려면 매개변수 확장 플래그를 zsh사용 하고 매개변수 확장 플래그를 분할하면 됩니다.js

words=(-n mynamespace) # two arguments in an array variable
export ENV_VAR=${(j[ ])mynamespace} # joined into an environment variable

그런 다음 환경 변수가 쉘 변수에 매핑된 해당 환경 내에서 호출된 다른 환경에서 zsh호출됩니다 .ENV_VAR$ENV_VAR

words=(${(s[ ])ENV_VAR}) # split back into an array on space

매개변수 확장 플래그가 없는 bash 또는 ksh93에서는 "${array[*]}"첫 번째 문자(기본값에서는 공백 문자임)를 사용하여 배열 요소를 연결하고 분할+glob을 사용하여 분할할 수 있습니다.$IFS

words=(-n mynamespace) # two arguments in an array variable
IFS=' '
export ENV_VAR="${words[*]}" # joined into an environment variable

다른 bash/ ksh93그 환경에서:

IFS=' '
set -o noglob
words=($ENV_VAR) # leaving a variable unquoted is split+glob in bash/ksh93!
                 # here with glob disabled above.

에서도 이 작업을 수행할 수 있지만 zshsh 또는 ksh 에뮬레이션 모드에서만 가능합니다. 기본적으로 zsh는 인용되지 않은 매개변수 확장 시 분할+glob을 수행하지 않습니다. $=var분할, $~var글로빙의 경우 각 매개변수를 명시적으로 요청해야 합니다. 따라서 어떤 이유로 j/ 매개변수 확장 플래그 대신 IFS 분할을 사용하려는 경우 s다음을 수행할 수 있습니다.

IFS=' '
words=($=ENV_VAR) # explicitly request IFS-splitting, here on space only.
                  # no need to disable globbing globally like in ksh93/bash/yash
                  # as globbing is not done implicitly by default upon
                  # parameter expansion in zsh.

지금은 모르겠지만 kubectl표준 방식으로 옵션을 구문 분석하는 애플리케이션(예: 표준 getopt()C 함수), 인수가 있는 옵션(예: with )의 경우 두 개의 인수 또는 하나의 인수를 grep -e expression전달할 수 있으므로 여기서는 스칼라 변수에 해당 인수 와 해당 인수를 저장할 수 있습니다 .-eexpression-eexpression-nmynamespace

option=-nmynamespace
kubectl get pods $option

(비어 있는 경우 $option참조되지 않으므로 확장으로 인해 인수가 전달되지 않습니다 kubectl. 이 점(및 빈 배열 요소가 삭제된다는 사실)은 버그 기능으로 간주될 수 있지만 여기에 있습니다. 정확히 당신이 원하는 것).

관련 정보