나는 함께 일하고 있다쿠벡텔그리고 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()
이를 검색하기 위해 다음과 같은 것을 사용합니다( 또는 ENVIRON
of 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
사용 하고 매개변수 확장 플래그를 분할하면 됩니다.j
s
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.
에서도 이 작업을 수행할 수 있지만 zsh
sh 또는 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
전달할 수 있으므로 여기서는 스칼라 변수에 해당 인수 와 해당 인수를 저장할 수 있습니다 .-e
expression
-eexpression
-n
mynamespace
option=-nmynamespace
kubectl get pods $option
(비어 있는 경우 $option
참조되지 않으므로 확장으로 인해 인수가 전달되지 않습니다 kubectl
. 이 점(및 빈 배열 요소가 삭제된다는 사실)은 버그 기능으로 간주될 수 있지만 여기에 있습니다. 정확히 당신이 원하는 것).