위치 매개변수의 단어 분사

위치 매개변수의 단어 분사

다음 예를 고려하십시오.

IFS=:
x="a   :b"   # three spaces
echo ["$x"]  # no word splitting
# [a   :b]   # as is
echo [$x]    # word splitting 
# [a    b]   # four spaces

단어 분리기는 콜론으로 구분된 단어 "a "(공백 3개)와 를 식별한 "b"다음, echo사이에 있는 공백이 단어를 연결합니다. 하지만 값을 함수 인수로
사용하면 결과를 해석하기 어렵다는 것을 알게 되었습니다 .$x

args(){ echo ["$*"];}
args a   :b  # three spaces
# [a::b]

그리고:

args(){ echo [$*];}
args a   :b  # three spaces
# [a  b]     # two spaces

$*모든 위치 인수 조합의 값으로 확장됩니다. 또한 IFS 변수 값의 첫 번째 문자는 where "$*"와 동일합니다 ."$1c$2"c

args(){ echo ["$1"]["$2"]; }
args a   :b  # three spaces
# [a][:b]

그리고:

args(){ echo [$1][$2]; }
args a   :b  # three spaces
# [a][ b]   

따옴표가 없는 확장이 있는 경우 항상 토큰화를 수행해야 합니다. 여기서 "$1"합계 는 동일하며 $1두 경우 모두 :구분 기호를 사용하지 않습니다. [$2]-> [ b]둘 다 확실하지 않습니다.

아마도 IFS 분할을 적용하기 전에 다른 토큰화 규칙이 사용되지만 찾을 수 없습니다.

답변1

토큰화는 최신 Bourne 유사 셸에서 따옴표가 없는 확장(인수 확장, 산술 확장 및 명령 대체)에서만 작동합니다( zsh에뮬레이션 모드를 사용하지 않는 한 명령 대체만 가능).

이 작업을 수행할 때:

args a    :b

전혀 관련된 분사가 없습니다.

쉘 구문 분석은 이를 토큰화하고 첫 번째 것이 키워드 중 하나가 아니라는 것을 발견하므로 , 및 args3 개의 인수가 있는 간단한 명령입니다 . 공간의 크기는 별 차이가 없을 것입니다. 공백뿐만 아니라 탭도 포함되며 일부 셸(예: 또는 )에서는 무엇이든 고려됩니다.a:byashbash공백귀하의 로케일에서 (귀하의 경우에는 bash멀티 바이트가 아님).

Bourne 쉘에서도 토큰화는 따옴표가 없는 명령 인수에 적용되며 확장 결과인지 여부에 관계없이 수행됩니다.위에(나중에) 토큰화 및 구문 분석.

Bourne 쉘에서는

IFS=i
while bib=did edit foo

그렇지 않습니다분석하다지금 바로:

"wh" "le b" "b=d" "d ed" "t foo"

그러나 먼저 while간단한 명령 으로서 edit해당 간단한 명령에 대한 단어( bid=did할당된 단어가 아닌 매개 변수이기 때문에)는 다음과 같습니다.더 멀리인수가 3개인 명령 의 경우 ed합계 가 루프 의 조건으로 실행되도록 합계 로 변환합니다 .tededtfoowhile

분사는아니요구문 분석의 일부입니다. 이는 인수( for루프 단어, 배열 및 일부 쉘의 리디렉션 대상 및다른 상황) 인용되지 않은 부분에 대해 설명합니다. 더 헷갈리는 건 이미 끝난 일이라는 거다.암묵적으로. 당신은 그것을 하지 않고 cmd split($x), 당신은 그것을 하고 cmd $x, 그리고 split()(실제로glob(split()))은 암시적입니다. 에서는 매개변수 확장이 존재 하는 경우 zsh이를 명시적으로 요청해야 합니다 ( 가위 모양).split($x)$=x$=

이제 예를 들면 다음과 같습니다.

args(){ echo ["$*"];}
args a   :b  # three spaces
# [a::b]

a첫 번째 문자가 제공되는 :bJoin 인수 ( 와일드카드 연산자이므로 여기서 사용하는 것은 좋지 않습니다 ).args$IFSa::b[...]

args(){ echo [$*];}
args a   :b  # three spaces
# [a  b]     # two spaces

$*(포함 )은 , 빈 문자열 및 a::b로 분할됩니다 . 그래서 이것은:ab

echo '[a' '' 'b]'
args(){ echo ["$1"]["$2"]; }
args a   :b  # three spaces
# [a][:b]

분사가 없기 때문에 놀라운 일은 아닙니다.

args(){ echo [$1][$2]; }
args a   :b  # three spaces
# [a][ b]   

이것은 다음과 같습니다:

 echo '[a]' '[' 'b]'

as $2( :b)는 빈 문자열과 로 분할됩니다 b.

구현 간의 차이점을 확인할 수 있는 상황 중 하나는 $IFSnull인 경우입니다.

존재하다:

set a b
IFS=
printf '<%s>\n' $*

일부 쉘(대부분 현재)에서는 다음을 볼 수 있습니다.

<a>
<b>

<ab>이러한 "$*"확장 에도 불구 하고 ab이러한 쉘은 여전히 ​​이러한 매개변수를 위치 매개변수 a와 별도로 유지하며 b이는 이제 최신 버전의 표준에서 POSIX 요구사항입니다.

이렇게 하면:

set a b
IFS=
var="$*" # note that the behaviour for var=$* is unspecified
printf '<%s>\n' $var

에 할당하면 및 두 개의 개별 매개변수에 대한 정보가 <ab>손실되는 것을 알 수 있습니다.ab$var


1 물론 단어를 구분하는 것은 공백만이 아닙니다. 쉘 구문의 특수 토큰도 사용할 수 있으며 그 목록은 상황에 따라 다릅니다. 대부분의 경우 , |, ||, &, ;개행 문자, <, >, >>...는 단어를 구분합니다. 예를 들어 ksh93다음과 같이 공백이 없는 명령을 작성할 수 있습니다.

while({([[(:)]])})&&((1||1))do(:);uname<&2|tee>(rev)file;done

관련 정보