2010-07-27 4 views
42

처음으로 Bash 완료를 작성하는 데 찌르는 듯하고, 역 참조 배역 배열 (${array[@]}${array[*]})에 대해 혼란스러워합니다.

_switch() 
{ 
    local cur perls 
    local ROOT=${PERLBREW_ROOT:-$HOME/perl5/perlbrew} 
    COMPREPLY=() 
    cur=${COMP_WORDS[COMP_CWORD]} 
    perls=($ROOT/perls/perl-*) 
    # remove all but the final part of the name 
    perls=(${perls[*]##*/}) 

    COMPREPLY=($(compgen -W "${perls[*]} /usr/bin/perl" -- ${cur})) 
} 

배쉬의 documentation says :

배열의 요소 수

여기에 코드의 관련 덩어리가 (이 방법에 의해 작동하지만, 내가 더 잘 이해하고 싶습니다)입니다 $ {name [subscript]}를 사용하여 참조 할 수 있습니다. 중괄호는 쉘의 파일 이름 확장 연산자와의 충돌을 피하기 위해 필요합니다. 첨자가 '@'또는 '*'인 경우 단어는 배열 이름의 모든 멤버로 확장됩니다. 이 첨자는 단어가 큰 따옴표 안에 나타날 때만 다릅니다. 단어가 큰 따옴표로 묶여 있으면 $ {name [*]}은 IFS 변수의 첫 번째 문자로 구분 된 각 배열 구성원의 값으로 단일 단어로 확장되고 $ {name [@]}는 name의 각 요소를 확장합니다 별도의 단어로

지금 나는 compgen -W이 가능한 대안의 단어 목록을 포함하는 문자열을 기대하는 이해 생각하지만,이 상황에서 나는 {이름은 [@]가} 별도의 단어 이름의 각 요소를 확장 무엇을 "$ 이해가 안 돼요 "의미합니다.

짧은 이야기 : ${array[*]} 작품; ${array[@]} 않습니다. 이유를 알고 싶습니다. 정확히 ${array[@]}이 무엇으로 확장되는지 더 잘 이해하고 싶습니다.

답변

53

(이 Kaleb 페더슨의 대답에 내 의견의 확장은 -보다 일반적인 동안 그 답을 볼 수 대 [*].

bash (또는 유사한 쉘)는 명령 행을 구문 분석 할 때이를 일련의 "단어"(나중에 "혼동을 피하기 위해"쉘 단어 "라고 함)로 분할합니다. 일반적으로 셸 단어는 공백 (또는 다른 공백)으로 구분되지만 이스케이프 또는 인용을 사용하면 셸 단어에 공백을 포함 할 수 있습니다. [@][*] 확장 된 큰 따옴표로 묶인 배열의 차이는 "${myarray[@]}"은 배열의 각 요소가 별도의 셸 단어로 취급되는 반면 "${myarray[*]}"은 배열의 모든 요소가 분리 된 단일 셸 단어가된다는 점입니다 공백 (또는 IFS의 첫 번째 문자가 무엇이든간에).

일반적으로 [@] 동작이 원하는 것입니다. perls=(perl-one perl-two)이 있고 ls "${perls[*]}"을 사용한다고 가정하면 ls "perl-one perl-two"과 동일하며 perl-one perl-two이라는 단일 파일을 찾습니다. 이는 아마도 원하는 것이 아닙니다. ls "${perls[@]}"ls "perl-one" "perl-two"과 동일하므로 유용 할 가능성이 훨씬 높습니다.

compgen으로 완료 단어 목록 (쉼표 단어와 혼동하지 않기 위해 comp-words라고 부름)을 제공하는 것은 다릅니다. -W 옵션에는 comp-words 목록이 필요하지만 comp-words가 공백으로 구분 된 단일 셸 단어 형식이어야합니다. 인수를 항상 취하는 명령 옵션 (적어도 내가 아는 한)은 단일 쉘 단어를 사용합니다. 그렇지 않으면 옵션 끝의 인수와 일반 명령 인수 (/ 기타)를 알 수있는 방법이 없습니다. 옵션 플래그)가 시작됩니다. 구체적으로

: 당신이 원하는 않는 ...

compgen -W "perl-one perl-two /usr/bin/perl" -- ${cur} 

:

perls=(perl-one perl-two) 
compgen -W "${perls[*]} /usr/bin/perl" -- ${cur} 

은 동일합니다. 반면에,

perls=(perl-one perl-two) 
compgen -W "${perls[@]} /usr/bin/perl" -- ${cur} 

은 동일합니다 :

완전한 넌센스입니다
compgen -W "perl-one" "perl-two /usr/bin/perl" -- ${cur} 

... "펄 - 하나"-W 플래그에 부착 된 전용 COMP-단어이며, compgen이 완료 될 문자열로 취할 수있는 첫 번째 실제 인수는 "perl-two/usr/bin/perl"입니다. 나는 compgen이 여분의 인수 ("-"와 $ cur에있는 것이 무엇이든)가 주어 졌다고 불평 할 것이지만 분명히 그것들을 무시한다.

+2

이것은 훌륭합니다. 감사. 나는 그것이 정말로 더 크게 소리내어줬으면 좋겠지 만, 적어도 그것이 작동하지 않는 이유를 분명히하고있다. – Telemachus

31

귀하의 제목은 ${array[@]}${array[*]}입니다.하지만 $array[*] 대 약 $array[@] 일 정도로 약간 혼란 스럽습니다.

배열 변수를 인용하고 @을 아래 첨자로 사용하는 경우 배열의 각 요소는 그 안에 존재할 수있는 공백 (실제로는 $IFS 중 하나)에 관계없이 전체 콘텐츠로 확장됩니다. 함유량. 별표 (*)를 인용 부호로 사용할지 여부에 관계없이 아래 첨자로 사용하면 각 배열 요소의 내용을 $IFS으로 분리하여 생성 된 새로운 내용으로 확장 될 수 있습니다.

다음은 예제 스크립트입니다 :

#!/bin/sh 

myarray[0]="one" 
myarray[1]="two" 
myarray[3]="three four" 

echo "with quotes around myarray[*]" 
for x in "${myarray[*]}"; do 
     echo "ARG[*]: '$x'" 
done 

echo "with quotes around myarray[@]" 
for x in "${myarray[@]}"; do 
     echo "ARG[@]: '$x'" 
done 

echo "without quotes around myarray[*]" 
for x in ${myarray[*]}; do 
     echo "ARG[*]: '$x'" 
done 

echo "without quotes around myarray[@]" 
for x in ${myarray[@]}; do 
     echo "ARG[@]: '$x'" 
done 

그리고 여기 출력의의 :

with quotes around myarray[*] 
ARG[*]: 'one two three four' 
with quotes around myarray[@] 
ARG[@]: 'one' 
ARG[@]: 'two' 
ARG[@]: 'three four' 
without quotes around myarray[*] 
ARG[*]: 'one' 
ARG[*]: 'two' 
ARG[*]: 'three' 
ARG[*]: 'four' 
without quotes around myarray[@] 
ARG[@]: 'one' 
ARG[@]: 'two' 
ARG[@]: 'three' 
ARG[@]: 'four' 

내가 개인적으로 보통 "${myarray[@]}"를 원한다. 이제 질문의 두 번째 부분 인 ${array[@]}$array[@]에 대한 답변입니다.

당신이 인용 한 bash는 문서, 인용 :

중괄호가 쉘의 파일 이름 확장 운영자와의 충돌을 피하기 위해 요구된다. 당신이 $myarray[@] 할 때, 달러 기호가 단단히 myarray에 바인딩

$ myarray= 
$ myarray[0]="one" 
$ myarray[1]="two" 
$ echo ${myarray[@]} 
one two 

그러나, 그래서 그것은 [@] 전에 평가됩니다.예를 들어 문서에 언급 된 바와 같이

$ ls $myarray[@] 
ls: cannot access one[@]: No such file or directory 

그러나, 브래킷은 파일 이름 확장이다, 그래서 이것을 시도하자 :

$ touch [email protected] 
$ ls $myarray[@] 
[email protected] 

이제 우리는 파일 이름 확장이 $myarray exapansion 후에 일어난 것을 볼 수있다 . 첨자없이

그리고 한 번 더 참고, $myarray 배열의 첫 번째 값으로 확장 :

$ myarray[0]="one four" 
$ echo $myarray[5] 
one four[5] 
+1

[this] (http : // stackoverflow.'IFS'가'@'과'*'에 따라 다르게 출력에 영향을 미치는 방법과 quoted와 unquoted를 비교하는 방법에 대한 정보를 제공합니다 (예 : com/questions/3307672/whats-the-difference-in-unix/3308046 # 3308046). –

+0

나는이 상황에서 매우 중요하기 때문에 사과드립니다. 그러나 나는 항상'$ {array [*]}'또는'$ {array [@]} '을 의미했습니다. 중괄호가 없다는 것은 단순히 부주의였다. 그 외에도,'compgen' 명령에서'$ {array [*]}'가 무엇을 확장 할 수 있는지 설명 할 수 있습니까? 즉, 그 맥락에서 각 요소를 개별적으로 확장한다는 것은 무엇을 의미합니까? – Telemachus

+0

다른 말로하면, (거의 모든 소스와 마찬가지로) 당신은'$ {array [@]}'이 일반적으로 사용된다고 말합니다. 내가 이해하려고 노력하는 것은이 경우 * $ {array [*]}만이 작동하는 이유입니다. – Telemachus