쉘에서 $@의 데이터 구조는 무엇입니까?

쉘에서 $@의 데이터 구조는 무엇입니까?

우리는 일반적으로 $@$0을 제외한 모든 매개변수를 나타내는 데 사용합니다. 그런데 $@데이터 구조가 무엇인지 모르겠습니다 .

$*큰따옴표가 포함되면 다르게 동작하는 이유는 무엇입니까? 누구든지 통역사 수준의 설명을 제공할 수 있습니까?

for 루프에서 반복될 수 있으므로 배열처럼 보입니다. 그러나 이는 simple 과 똑같이 작동합니다 echo $@. 배열인 경우 첫 번째 요소만 표시됩니다. 셸의 제한으로 인해 수행할 실험 코드를 더 이상 작성할 수 없습니다.

사이의 차이이 게시물: 이 문서에서는 $@의 동작이 의 동작과 다르다는 것을 보여줍니다 $*. 하지만 데이터 유형이 혼란 스럽습니다 $@. Python과 같은 해석 언어인 Shell은 일련의 기본 유형 측면에서 데이터를 표현해야 합니다. 즉, $@이 컴퓨터 메모리에 어떻게 저장되는지 알고 싶습니다.

문자열인가요, 여러 줄 문자열인가요, 아니면 배열인가요?

유일한 데이터 유형인 경우 맞춤 변수를 해당 유형의 인스턴스로 정의할 수 있나요?

답변1

이것은 Bourne 쉘 해킹으로 시작되었습니다. Bourne 셸에서 forIFS 단어 분할(토큰화 후)은 목록 컨텍스트(명령줄 인수 또는 반복되는 단어)의 모든 단어에 대해 수행됩니다. 당신이 가지고 있다면:

IFS=i var=file2.txt
edit file.txt $var

두 번째 줄은 3개의 단어로 태그가 지정되고 $var확장되며, 세 단어 모두에 대해 분할+glob이 수행되므로 결국 , , ,를 인수로 ed사용하여 실행 하게 됩니다.tfle.txtfle2.txt

그 일부를 인용하면 분할+글로브를 방지할 수 있습니다. Bourne 쉘은 원래 내부적으로 8번째 비트를 설정하여 어떤 문자가 인용되었는지 기억했습니다(나중에 Unix가 8비트로 깔끔해졌을 때 변경되었지만 쉘은 여전히 ​​어떤 바이트가 인용되었는지 기억하는 것과 유사한 작업을 수행했습니다).

둘 다 사이에 공백이 있는 위치 매개변수의 연결 $*입니다 . $@그러나 $@큰따옴표 안에 있는 경우에는 특별하게 처리됩니다. $1포함 foo bar$2포함된 경우 baz다음 "$@"으로 확장됩니다.

foo bar baz
^^^^^^^ ^^^

( ^위의 s는 비트 8이 설정된 문자를 나타냅니다.) 여기서 첫 번째 공백은 인용되지만(비트 8이 설정됨) 두 번째 공백(단어 사이에 추가된 공백)은 인용되지 않습니다.

IFS 분할은 인수 분리를 담당합니다( $IFS기본적으로 공백 문자로 가정). 이는 $*이전 버전인 Mashey 셸이 확장된 방식 과 유사합니다 (자체는 Thomson 셸을 기반으로 한 반면 Bourne 셸은 처음부터 작성되었습니다).

이는 Bourne 쉘에서 위치 인수 목록이 비어 있는 이유를 설명합니다 ( 빈 위치 매개변수로 "$@"문제를 해결해야 합니까 ?). ${1+"$@"}공백 문자가 포함되어 있지 않으면 아무런 효과가 없습니다 "$@".$IFS

목적은 인수 목록을 다른 명령에 그대로 전달할 수 있도록 하는 것입니다. 그러나 이는 $IFS빈 목록, 빈 요소 또는 공백이 포함되지 않은 경우 제대로 작동하지 않습니다(처음 두 문제는 이후 버전에서 결국 수정되었습니다).

POSIX 사양의 기반이 되는 Korn 쉘은 이 동작을 여러 가지 방법으로 변경합니다.

  • IFS 분할은 따옴표가 없는 확장 결과에 대해서만 수행됩니다( edit위 예와 같은 문자 그대로의 단어에 대해서는 수행되지 않음).file.txt
  • $*비어 있으면 $@첫 번째 문자나 공백으로 연결되지만 인용된 연산자의 경우 Bourne 쉘에서와 같이 연결 연산자가 인용 해제되고 인용된 경우 비어 있으면 구분 기호가 아닌 위치 인수가 추가됩니다.$IFS$IFS"$@""$*"IFS
  • 배열에 대한 지원을 추가하고 ${array[@]} ${array[*]}Bourne을 연상시키지만 $*인덱스 $@1 대신 0에서 시작하고 희박합니다(연관 배열과 유사함). 즉 $@실제로 ksh 배열로 처리 할 수 없음 을 의미합니다( csh// rc에 여기서 /는 일반 배열입니다).zshfishyash$argv$*
  • 빈 요소는 유지됩니다.
  • "$@"0 인 경우 $#이제 빈 문자열 대신 빈 문자열로 확장됩니다. "$@"이는 비어 있지 않으면 공백이 없을 때 유효합니다. 비어 있으면 와일드카드 없이 따옴표가 없는 문자열이 단일 인수로 확장됩니다(위치 인수가 공백으로 연결됨).$IFSIFS$*$IFS

ksh93은 위의 ​​나머지 문제를 해결합니다. ksh93에서는 의 값에 관계없이 분리된 위치 인수 목록으로 확장된 $*다음 목록 컨텍스트에서 추가로 분할+글로브+중괄호 확장되어 첫 번째와 연결됩니다.$@$IFS$*바이트(문자가 아님) of 는 $IFS"$@"에 관계없이 목록 컨텍스트의 위치 인수 목록으로 확장됩니다 $IFS. var=$@in 과 같은 비목록 컨텍스트에서는 $@의 값이 무엇이든 공백과 연결됩니다 $IFS.

bash어레이는 ksh 어레이 이후에 설계되었습니다. 차이점은 다음과 같습니다.

  • 인용되지 않은 확장 중에는 중괄호 확장이 없습니다.
  • 의 첫 번째 문자는 $IFSfor 바이트를 대체합니다.
  • $*목록이 아닌 컨텍스트에서 null이 인용되지 않은 경우 확장과 같은 일부 코너 케이스 차이점이 있습니다 $IFS.

POSIX 사양은 매우 모호했지만 이제는 bash 동작을 어느 정도 지정합니다.

ksh다음과 같은 점에서 일반 배열과 다릅니다 bash.

  • 인덱스는 0 대신 1에서 시작합니다( "${@:0}"include 제외 $0(위치 인수가 아니며 쉘 및 함수 정의 방법에 따라 함수 이름이 지정되거나 지정되지 않음)).
  • 요소를 개별적으로 할당할 수 없습니다.
  • 희박하지 않으며 요소를 개별적으로 설정 해제할 수 없습니다.
  • shift사용할 수 있습니다.

배열이 zsh일반 배열인 경우 일반 배열로 처리됩니다 (희소하지 않고 ksh/bash를 제외한 다른 모든 쉘에서 인덱싱이 1부터 시작함). (호환성을 위해) 별칭이 있습니다. or와 동일합니다(인수는 of의 첫 번째 문자와 연결되지만 목록 컨텍스트에서는 별도로 유지됩니다). 코헨과 ​​유사하거나 특수 가공된 제품입니다.yash$*zsh$argvcsh$*$argv${argv[*]}$IFS"$@""${argv[@]}""${*[@]}"}

답변2

$@그런데 데이터 구조가 무엇인지 모르겠습니다 .

이는 위치 매개변수의 값으로 확장될 수 있는 특수 매개변수입니다. 하지만 용어가 까다롭습니다.

위치 인수를 a의 일부로 생각할 수 있으므로 독립적으로 액세스할 수 있고 연속된 자연수로 이름을 지정할 수 있는 $@다양한 요소( $1, ...)가 있습니다. $2이는 일반적으로 배열로 알려져 있습니다.

하지만 구문은 약간 이상하고 제한적입니다. 배열의 개별 요소는 개별적으로 수정할 수 없습니다. 대신 모든 것을 한 번에 설정해야 합니다. ( set -- "$@" foo추가된 값을 사용할 수도 있고 , set -- "${@:1:2}" foo "${@:3}"중간에 값을 추가할 수도 있습니다. 하지만 두 경우 모두 결과 목록 전체를 작성해야 합니다.)

$*큰따옴표를 포함할 때와 다르게 동작하는 이유는 무엇입니까 ?

그들의 행동이 다르게 정의되기 때문입니다.

그러나 이는 simple 과 똑같이 작동합니다 echo $@. 배열인 경우 첫 번째 요소만 표시됩니다.

a=(foo bar asdf); echo $a단지 출력을 의미한다면 foo이는 대부분 쉘 구문의 특이한 점이며 ksh 스타일 명명된 배열은 위치 인수 및 $@. Plain $a은 동일하므로 배열이든 단순 스칼라 변수 ${a[0]}이든 단일 스칼라 값에 대해 이전 버전과 호환되는 의미를 갖습니다 .a

@전체 목록을 참조하는 기호는 명명된 배열과 함께 재사용되며, 이것이 "${a[@]}"전체 목록을 얻는 방법입니다. 명명된 배열과 비교하여 with 를 사용하면 $@불필요한 중괄호와 대괄호, 이름이 생략됩니다.

혹은 즉, $@컴퓨터 메모리에 어떻게 저장되는지 알고 싶습니다.

이는 구현에 따라 다르며 관심 있는 특정 셸에 대한 소스 코드를 살펴봐야 합니다.

문자열인가요, 여러 줄 문자열인가요, 아니면 배열인가요?

주로 배열입니다. ksh 스타일의 명명된 배열과 달리 연속된 정수뿐만 아니라 음수가 아닌 임의의 정수를 인덱스로 가질 수 있습니다 $@. (즉, 명명된 배열은 희박할 수 있으며, 예를 들어 indexes 1, 3, 4, with 02누락 등을 가질 수 있습니다. 이는 위치 인수로는 불가능합니다.)

다른 요소로 확장될 수 있기 때문에 단일 문자열이 아니며 일반 변수 또는 위치 인수 중 하나( 요소 $@)에도 개행 문자가 포함될 수 있으므로 line 요소 호출도 올바르지 않습니다.

유일한 데이터 유형인 경우 맞춤 변수를 해당 유형의 인스턴스로 정의할 수 있나요?

아니요. 하지만 명명된 배열이 더 유용할 수 있습니다.

관련 정보