변수를 설정했어요TEMPP='-I ../dir1 -I ../dir2'
그럼 난 달려
gcc -M $TEMPP somefile.c
포함된 파일에 대한 검색 목록에 ../dir1
및 이 포함되지 않은 것으로 보이며 ../dir2
변수 시작 부분에 공백이 있는 경우(예:
TEMPP=' -I ../dir1 -I ../dir2'
오류가 보고됩니다.
gcc: -I ../common1 -I ../encrypt: No such file or directory
그래서 변수를 파일로 취급하는 것 같습니다.
아마도 이 문제를 피하기 위해 디렉토리를 분리할 수 있을 것입니다. 그러나 포함된 디렉토리는 dirs
다른 명령에 의해 생성되며 숫자는 일정하지 않습니다.
그렇다면 명령의 변수를 리터럴로 처리하고 정수 문자열이나 파일 이름이 아닌 명령줄에서 수동 입력처럼 보이도록 하려면 어떻게 해야 할까요?
zsh
글쎄... 이것은 bash에서만 발생 하지만 bash에서는 잘 작동한다는 것을 알았습니다 . 아마도 zsh
변수 확장이 특별할 수도 있습니다.
따라서 누구든지 zsh에서 이 작업을 훌륭하게 작동시키는 방법을 알려줄 수 있다면 매우 감사할 것입니다. 그렇지 않으면 bash에서만 이 작업을 수행할 수 있습니다.
답변1
"$TEMPP"
나는 공백이 해석되는지 여부를 제어하려고 노력하고 있다고 생각합니다. (이것은 GCC 문제가 아니라 쉘이 명령줄을 구문 분석하는 문제입니다.)
이것이 bash
하는 일:
$ F="foo bar baz"
$ for f in $F; do echo $f; done
foo
bar
baz
이것이 zsh
하는 일:
$ F="foo bar baz"
$ for f in $F; do echo $f; done
foo bar baz
zsh
공백을 설명 해야합니다 . zsh에서 이를 수행하는 우아한 방법이 있을 수 있습니다(모르겠지만 질문의 제목을 바꾸고 태그를 지정하면 더 유용한 답변을 얻을 수 있습니다). 이렇게 하면 문제가 해결되지만 문제에 대한 부담은 약간 큽니다.
eval gcc -M $TEMPP somefile.c
답변2
zsh에서는 다른 Bourne 스타일 쉘과 달리 변수 대체 결과가 와일드카드 패턴으로 해석되는 단어로 분할되지 않습니다. 따라서 zsh에서 작성하면
a='hello *.txt'
echo $a
그러면 hello *.txt
다른 쉘과 달리 다음과 같은 것을 보게 될 것입니다 hello bar.txt foo.txt
.
개인에 대해 단어 분할을 설정할 수 있습니다.확장그리고 $=TEMPP
. setopt sh_word_split
모든 확장자에 대해 단어 분리를 사용하거나 설정할 수 있습니다 emulate sh
.
이러한 명령을 makefile에 넣고 진정한 Bourne 스타일 쉘(설치된 모든 것 /bin/sh
)에서 이를 실행하도록 해야 합니다. 대화형 사용 및 자체 스크립트를 위해 zsh를 예약하세요.
답변3
가변 개수의 값을 보유하는 변수를 배열이라고 합니다.
var=value
스칼라 변수 할당 구문은 다음과 같습니다.하나값은 a에 할당됩니다.스칼라 변수.
var=( one two 'three or 3' )
예배열 변수값을 할당할 수 있는 할당 구문임의의 숫자(심지어 0²) 값배열/목록 변수.
var[n]=foo
스칼라 할당 구문이기도 하지만 할당은하나배열의 n번째 요소 값입니다 .
원하는 내용은 다음과 같습니다.
extra_options=( -I ../dir1 -I ../dir2 -I '/opt/my software/include' )
gcc -M $extra_options somefile.c
확장 은 $extra_options
배열의 빈 요소 $extra_options
(있는 경우) 를 건너 $scalar
뜁니다 .아니요비어 있으면 인수는 대신 빈 요소입니다 $scalar
.
"$scalar"
빈 요소를 보존하려면 or "$array[@]"
( "${(@)array}"
또는 "${array[@]}"
bash와 같은 ksh 유사 쉘과 호환되고 "$@"
Bourne 쉘을 연상시킴)이 필요합니다 .
다른 Bourne과 유사한 쉘에서는 다음 사항에 유의하세요.
TEMPP='-I ../dir1 -I ../dir2'
gcc -M $TEMPP somefile.c
$TEMPP
암묵적으로 소위 말하는 것을 경험하십시오.분할+전역$TEMPP
연산자를 사용하면 (다행히도!) 의 값이 셸 코드에 그대로 포함된 것처럼 나타나지 않습니다 gcc -M -I ../dir1 -I ../dir2 somefile.c
.
사례 4 인 경우 다음과 같습니다.
TEMPP='foo>/etc/passwd;reboot' # or '$(reboot>/etc/passwd)'
echo $TEMPP
/etc/passwd
예를 들어 덮어쓰고 다시 시작합니다. 변수 확장 중에는 쉘 구문( ;
, >
연산자, ${...}
확장 $(...)
, 따옴표 포함)이 인식되거나 처리되지 않습니다. 그러나 zsh나 기타 좀 더 정상적인 최신 쉘(rc, es, fish, akanga...) 또는 기타 프로그래밍 언어처럼 있는 그대로 확장되지는 않지만 대신 분할+glob 연산자를 사용합니다.
값은 $TEMPP
문자만을 기준으로 분할된 $IFS
다음 와일드카드로 표시됩니다(파일 이름 생성 또는 경로 이름 확장이라고도 함). 이는 다음을 의미합니다.
TEMPP='-I ../dir1 -I ../dir2'
gcc -M $TEMPP somefile.c
이는 줄 $IFS
을 해석할 때 , 공백 문자가 포함된 경우에만 작동 gcc...
하고 다른 문자는 포함되지 않습니다 $TEMPP
(다행히 기본값인 경우 $IFS
). 예를 들어 가 포함된 경우 , $IFS
및 i
매개 변수 를 gcc
사용하여 호출됩니다 .-I ../d
r1 -I ../d
r2
그리고:
TEMPP='-I ../dir1 -I ../dir2 -I "/opt/my software/include"'
gcc -M $TEMPP somefile.c
셸 구문(예: 따옴표)을 해석하지 않고 분할만 수행하기 때문에 작동하지 않습니다. $IFS
따라서 공백이 포함된 매개변수를 전달해야 하는 경우 분할을 위해 다른 구분 기호를 사용해야 합니다. 예:
TEMPP='-I,../dir1,-I,../dir2,-I,/opt/my software/include'
IFS=,
gcc -M $TEMPP somefile.c
예를 들어. 값에 *
, , 등 ?
의 와일드카드 연산자가 포함된 경우 확장하기 전에 명령을 실행하여 와일드카드 문자가 확장되지 않도록 [...]
해야 합니다 . set -o noglob
당신은 또한 볼 수 있습니다bash/POSIX 쉘에서 변수를 인용하는 것을 잊어버리는 보안 위험Bourne과 유사한 쉘(zsh 제외)의 잘못된 디자인이 보안에 미치는 영향.
zsh에서 -splitting 및/또는 globbing을 원할 경우 $IFS
(그러나 일반적으로 대부분의 다른 최신 쉘처럼 zsh에 배열이 없음) 요청해야 합니다.분명히, $=scalar
분할 on 은 $IFS
내용 $~scalar
을 $scalar
패턴과 와일드카드 또는 둘 다로 처리하므로 다른 Bourne 유사 쉘 $=~scalar
과 동일합니다 .$scalar
를 사용하는 대신 ${(s[whatever])scalar}
구분 기호로 분할을 참조 하고 줄 eed(개행 문자라고도 함) 또는 NUL 에서 분할하는 방법을 간략하게 참조하세요 .$IFS
${(f)scalar}
${(0)scalar}
f
zsh
다른 Bourne형 또는 Korn형 셸용으로 작성된 코드를 해석 해야 하는 경우 해당 코드를 사용 sh
하거나 ksh
에뮬레이트할 수 있습니다. 여기서 이러한 셸과의 호환성은 다음을 통해 향상됩니다.
emulate ksh
: 시뮬레이션을 명시적으로 변경합니다(emulate zsh
기본 정상 모드를 복원하지만).emulate -L ksh
: 동일하지만L
로컬에서만 가능합니다(예: 현재 함수 내에서).emulate ksh -c 'ksh/bash code here'
아니면emulate ksh -c 'source some-ksh-or-bash-script'
해당 시뮬레이션 모드에서 주어진 코드를 해석하면 됩니다.
sh 또는 ksh 에뮬레이션에서 IFS 분할 및 와일드카드 지정은 sh/ksh/bash에서와 같이 목록 컨텍스트에서 인용되지 않은 인수 확장 시 암시적으로 수행됩니다(그리고 쉘 동작에 영향을 미치는 다른 shwordsplit
많은 globsubst
옵션은 다음과 같이 작동하도록 조정됩니다. 가능한).
1 set var = ( one two 'three or 3' )
배열을 도입한 최초의 셸인 csh에서 영감을 얻었으며 나중에 set -A var one two 'three or 3'
ksh93(이전 버전의 ksh에도 이 기능이 있었음에도 불구하고), bash 또는 yash와 같은 다른 셸에 의해 복사되었습니다.
² 참고: ksh93에는 배열을 먼저 생성하므로 var=()
선언이 없습니다 .var
화합물배열 변수 대신 변수.
입방체한 가지 예외를 제외하고 zsh 및 기타 모든 쉘에서:ksh (그리고 zsh 대신 ksh를 복사하는 bash), 여기서 배열 인덱스는 0에서 시작하고 배열은 희소하므로 인덱스 0의 요소도 설정되면 두 번째 요소 가 모두 array[1]=x
할당됩니다. array[123]=x
추가 설정 없이 요소 범위는 0~122입니다.
사실 , 이것은 70년대 초반 최초의 (매우 단순하고 원시적인) Unix 쉘의 경우였습니다. 이 쉘에는 변수도 없고 명령 대체도 없었지만 $1
... $9
이와 같은 확장된 위치 인수가 있었습니다.