다음 예를 고려하십시오.
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
전혀 관련된 분사가 없습니다.
쉘 구문 분석은 이를 토큰화하고 첫 번째 것이 키워드 중 하나가 아니라는 것을 발견하므로 , 및 args
3 개의 인수가 있는 간단한 명령입니다 . 공간의 크기는 별 차이가 없을 것입니다. 공백뿐만 아니라 탭도 포함되며 일부 셸(예: 또는 )에서는 무엇이든 고려됩니다.a
:b
yash
bash
공백귀하의 로케일에서 (귀하의 경우에는 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
합계 가 루프 의 조건으로 실행되도록 합계 로 변환합니다 .t
ed
ed
t
foo
while
분사는아니요구문 분석의 일부입니다. 이는 인수( for
루프 단어, 배열 및 일부 쉘의 리디렉션 대상 및다른 상황) 인용되지 않은 부분에 대해 설명합니다. 더 헷갈리는 건 이미 끝난 일이라는 거다.암묵적으로. 당신은 그것을 하지 않고 cmd split($x)
, 당신은 그것을 하고 cmd $x
, 그리고 split()
(실제로glob(split())
)은 암시적입니다. 에서는 매개변수 확장이 존재 하는 경우 zsh
이를 명시적으로 요청해야 합니다 ( 가위 모양).split($x)
$=x
$=
이제 예를 들면 다음과 같습니다.
args(){ echo ["$*"];} args a :b # three spaces # [a::b]
a
첫 번째 문자가 제공되는 :b
Join 인수 ( 와일드카드 연산자이므로 여기서 사용하는 것은 좋지 않습니다 ).args
$IFS
a::b
[...]
args(){ echo [$*];} args a :b # three spaces # [a b] # two spaces
$*
(포함 )은 , 빈 문자열 및 a::b
로 분할됩니다 . 그래서 이것은:a
b
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
.
구현 간의 차이점을 확인할 수 있는 상황 중 하나는 $IFS
null인 경우입니다.
존재하다:
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>
손실되는 것을 알 수 있습니다.a
b
$var
1 물론 단어를 구분하는 것은 공백만이 아닙니다. 쉘 구문의 특수 토큰도 사용할 수 있으며 그 목록은 상황에 따라 다릅니다. 대부분의 경우 , |
, ||
, &
, ;
개행 문자, <
, >
, >>
...는 단어를 구분합니다. 예를 들어 ksh93
다음과 같이 공백이 없는 명령을 작성할 수 있습니다.
while({([[(:)]])})&&((1||1))do(:);uname<&2|tee>(rev)file;done