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


13

우리는 보통 $@$ 0를 제외한 모든 인수를 나타내는 데 사용 합니다. 그러나 데이터 구조 $@가 무엇인지 모르겠습니다 .

$*큰 따옴표로 묶을 때 다르게 행동하는 이유는 무엇 입니까?

for 루프에서 반복 될 수 있으므로 배열 인 것 같습니다. 그러나 echo $@배열 인 경우 첫 번째 요소 만 표시됩니다. 쉘의 한계로 인해 더 많은 실험 코드를 작성하여 실행할 수 없습니다.

이 게시물의 차이점 :이 게시물 $@은와 다른 동작을 보여줍니다 $*. 그러나 나는 데이터 유형에 대해 궁금하다.$@ . 파이썬과 같은 해석 언어로서의 셸은 일련의 기본 유형에 따라 데이터를 나타내야합니다. 즉, $ @가 컴퓨터 메모리에 어떻게 저장되는지 알고 싶습니다.

문자열입니까, 여러 줄 문자열입니까? 아니면 배열입니까?

고유 한 데이터 유형 인 경우 사용자 정의 변수를이 유형의 인스턴스로 정의 할 수 있습니까?


1
가능한 중복 $ *와 $ @의 차이점
Haxiel

@Haxiel, 나는 그렇게 생각하지 않는다. 나는 내 게시물의 맨 아래에 그들의 차이점을 썼다.
davmos

당신은 더 나은과 출력의 차이를 테스트하여 제공 될 것입니다 printf '%s\n' "$@"printf '%s\n' "$*". echo가 하나 많은 경우 유틸리티는 인수에 상관없이 출력. 둘 다 (문자열) 배열이지만 큰 따옴표로 묶으면 다르게 동작합니다. 여러 줄 문자열 인 경우 여러 줄 문자열을 저장할 수 없습니다 (가능한). 해결하려는 문제가 확실하지 않습니다.
Kusalananda

2
귀하의 질문은 @var기본 스토리지 측면에서 변수가 Perl에 무엇인지 묻는 것과 같습니다 . 일반적인 Perl 프로그램의 관점에서 볼 때, 배열 / 목록으로 액세스 할 수 있다는 것 (및 목록이 예상되는 컨텍스트가 있다는 사실) 외에는 중요하지 않습니다.
Kusalananda

답변:


16

그것은 Bourne 쉘에서 핵으로 시작되었습니다. Bourne 쉘에서, IFS 단어 분리는 목록 컨텍스트의 모든 단어 (명령 행 인수 또는 for루프가 반복 되는 단어)에서 토큰 화 후 수행되었습니다 . 당신이 가지고 있다면 :

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

두 번째 줄이 세 단어에 tokenised 될 것이라고 $var확장 될 것이며, 실행 끝날 것 때문에 분할 + 글로브는, 모두 세 단어에서 수행 될 수 edt, f, le.txt, f, le2.txt인수로.

그 부분을 인용하면 스플릿 + 글로브를 막을 수 있습니다. Bourne 쉘은 처음에 내부적으로 8 번째 비트를 설정하여 인용 된 문자를 기억했습니다 (유닉스는 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위의 예)
  • $*$@상기 제의 문자 접합 $IFS또는 공간 $IFS인용 A에 대한 것을 제외하고 비어 "$@"그 소목은 본 셸처럼 인용되지 않은되고 인용 A의 "$*"경우 IFS비어는, 상기 위치 파라미터는 분리하지 않고 추가된다.
  • 그 어레이에 대한 지원을 추가하고, 함께 ${array[@]} ${array[*]}Bourne 씨의 연상 $*$@수단이되는 (연관 배열 등 이상)이지만 1 대신 indice 0에서 시작하고, 희소 $@정말 KSH 배열로 취급 될 수 없다 (비교 csh/ rc/ zsh/ fish/ yash어디 $argv/ $*정상의 배열).
  • 빈 요소는 유지됩니다.
  • "$@"when $#is 0은 이제 빈 문자열 대신에 아무것도 확장 하지 않으며 공백이 없을 때를 제외하고 공백을 포함하지 않을 "$@"때 작동합니다 . 와일드 카드가없는 인용 부호 는 비어 있을 때 하나의 인수 (위치 매개 변수가 공백과 결합되는)로 확장됩니다 .$IFSIFS$*$IFS

ksh93은 위의 ​​나머지 몇 가지 문제를 해결했습니다. 경우 ksh93에서 $*$@위치 파라미터의리스트로 확장의 값에 관계없이 분리 $IFS하고 상기 분리 + globbed + 브레이스 발포 목록 콘텍스트에서 $*제 합류 바이트 의 (성품) $IFS, "$@"목록에서 컨텍스트가 팽창에 위치 변수에 상관없이 값 $IFS. 비리스트 문맥에서처럼 var=$@, $@값에 관계없이 공간으로 결합된다 $IFS.

bash의 배열은 ksh 배열 이후에 설계되었습니다. 차이점은 다음과 같습니다.

  • 따옴표없는 확장시 괄호 확장 없음
  • $IFS바이트 대신에 첫 문자
  • $*목록이없는 컨텍스트에서 인용되지 않은 경우 의 확장과 같은 일부 경우의 차이 $IFS는 비어 있습니다.

POSIX 스펙은 꽤 모호했지만, 이제는 bash 동작을 지정합니다.

그것은 정상적인 배열에서 다르다 ksh또는 bash점에서 :

  • 인덱스는 0 대신 1부터 시작합니다 ( "${@:0}"포함하는 경우 $0(위치 매개 변수가 아님, 함수에서 함수의 이름을 제공하거나 쉘에 따라 또는 함수 정의 방법에 따라 다름)).
  • 요소를 개별적으로 할당 할 수 없습니다
  • 희소하지 않습니다. 요소를 개별적으로 설정 해제 할 수 없습니다
  • shift 사용할 수 있습니다.

에서 zsh또는 yash어레이 정상 배열 곳 (되지 성긴, 인덱스가 다른 쉘하지만 KSH / 떠들썩한 파티에서와 같은 하나의 시작에서), $*통상의 배열로 간주된다. zsh$argv대한 별칭으로 사용됩니다 (와의 호환성을 위해 csh). $*과 동일 $argv하거나 ${argv[*]}(인수의 첫 문자와 결합 $IFS하지만, 여전히 목록이 문맥에서 분리). "$@"같은 "${argv[@]}"또는 "${*[@]}"}의 : Korn 스타일의 특수 처리를 겪는다.


8

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

위치 매개 변수의 값으로 확장되는 특수 매개 변수입니다. 그러나 그것은 용어에 대한 핵심입니다.

위치 매개 변수를의 일부로 볼 수 $@있으므로 여러 개별 요소 ( $1, $2...)가 있으며, 독립적으로 액세스 할 수 있으며 연속적인 자연수로 이름이 지정됩니다. 일반적으로 배열이라고하는 것입니다.

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

$*큰 따옴표로 묶을 때 다르게 동작하는 이유 ,

그것들은 다르게 행동하도록 정의되어 있기 때문입니다.

그러나 echo $@배열 인 경우 첫 번째 요소 만 표시됩니다.

a=(foo bar asdf); echo $a그냥 출력 한다는 사실을 의미한다면 foo, 이것은 대부분 쉘 구문의 단점이며 ksh 스타일의 명명 된 배열이 위치 매개 변수 및보다 나중에 생성된다는 사실입니다 $@. 평문 $a은 배열 또는 단순 스칼라 변수인지 ${a[0]}여부에 관계없이 단일 스칼라 값의 역 호환 가능한 의미를 가지므로 동일 a합니다.

@전체 목록을 참조 기호는 점에서라는 이름의 배열을 다시 사용되었다 "${a[@]}"전체 목록을 얻을 수있는 방법입니다. 을 사용하여 명명 된 배열과 비교할 때 $@불필요한 괄호와 괄호 및 이름은 건너 뜁니다.

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

구현에 따라 관심있는 특정 쉘의 소스 코드를 봐야합니다.

문자열입니까, 여러 줄 문자열입니까? 아니면 배열입니까?

주로 배열입니다. ksh 스타일 명명 된 배열과는 다르지만와 같이 연속적인 정수뿐만 아니라 임의의 음이 아닌 정수를 인덱스로 가질 수 있기 때문입니다 $@. (즉, 명명 된 희소 배열, 그리고 예를 들어 인덱스를 가질 수있다 1, 3그리고 4,로 02누락. 즉, 위치 매개 변수에 불가능하다.)

개별 문자열로 확장 될 수 있기 때문에 단일 문자열이 아니며 정규 변수 또는 위치 매개 변수 중 하나 ( $@)가 줄 바꿈을 포함 할 수 있으므로 요소 행을 호출하는 것도 옳지 않습니다 .

고유 한 데이터 유형 인 경우 사용자 정의 변수를이 유형의 인스턴스로 정의 할 수 있습니까?

그러나 명명 된 배열은 어쨌든 더 유용 할 것입니다.


1
+1. TL : DR $@은 데이터 구조가 아니며 위치 매개 변수 데이터 구조 를 확장 하는 몇 가지 기능 / 운영자 중 하나입니다 .
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.