설명해주실 수 있나요? array=$( command )와 array=( $( command ) ) 사용 사이의 배열 동작의 차이점은 무엇입니까?

설명해주실 수 있나요? array=$( command )와 array=( $( command ) ) 사용 사이의 배열 동작의 차이점은 무엇입니까?

나는 명령 대체를 이해합니다. 나는 서브 쉘을 이해합니다. 서브쉘을 사용하면 배열의 구조가 변경되는 이유를 이해할 수 없습니다.

다음 명령 출력을 제공합니다. (openstack 명령 사용은 관련이 없습니다)

bash$ floating ip list -c 'Floating IP Address' -f value
172.25.250.106
172.25.250.107
172.25.250.101

배열에서 캡처를 시도했지만 모든 주소는 요소 0으로 끝납니다.

bash$ float=$( openstack floating ip list -c 'Floating IP Address' -f value )
bash$ echo ${float[@]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[@]}
1
bash$ echo ${float[0]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[0]}
44

전체 출력은 문자열로 캡처되며 요소로 구문 분석되지 않습니다. 나는 모든 단어가 하나의 요소가 되기를 기대합니다. 각 IP 주소가 참조되는지 확인하기 위해 이 작업을 반복하면(-f 값 대신 -f csv 사용) 결과는 동일합니다.

다음으로 명령 대체를 서브셸에 넣습니다.

bash$ unset float
bash$ float=( $( openstack floating ip list -c 'Floating IP Address' -f value ) )
bash$ echo ${float[@]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[@]}
3
echo ${float[0]}
172.25.250.106
echo ${#float[0]}
14

이것이 내가 원래 예상했던 동작입니다. 또한 배열을 빌드하기 위해 read 문을 사용하는 것이 예상대로 작동한다는 것을 확인했습니다.

bash$ unset float
bash$ read -a float <<< $( openstack floating ip list -c 'Floating IP Address' -f value )
bash$ echo ${float[@]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[@]}
3
echo ${float[0]}
172.25.250.106
echo ${#float[0]}
14

원래 명령 대체 작업을 보고 싶습니다. 필드 구분 기호를 먼저 설정해야 하는지 아니면 뭔가 빠졌는지 궁금합니다. 나는 행동의 차이를 일으키는 원인을 이해하려고 노력하고 있습니다.

답변1

float=$( openstack floating ip list -c 'Floating IP Address' -f value )

이것은배열 변수가 아닌 변수입니다. 문자열은 후행 줄 바꿈을 뺀 명령의 출력입니다.

문자열 변수를 배열로 사용하려고 하면 위치 0에 문자열 값이 있는 단일 요소 배열로 처리됩니다.

float=( $( openstack floating ip list -c 'Floating IP Address' -f value ) )

이것은 "명령 대체를 서브 쉘에 넣는" 것이 아닙니다. 명령 대체 자체가 $(…)서브쉘을 생성합니다. 주위의 괄호는 다른 하위 쉘을 생성하지 않고 배열을 생성합니다. 배열 내용은 명령의 출력을 취하고, 후행 줄 바꿈을 제거하고, 공백으로 구분된 단어 목록으로 분할하고, 하나 이상의 파일과 일치하는 와일드카드를 포함하는 이 목록의 모든 요소를 ​​일치하는 파일 이름 목록으로 대체하여 얻습니다.

명령이 예상되는 곳에 대괄호를 배치하면 하위 쉘이 생성됩니다. 에서 var=(…)등호 뒤에 오는 것은 명령이 아니라 할당된 값입니다. 이 경우 대괄호는 값이 배열임을 나타냅니다.

답변2

float=$( openstack floating ip list -c 'Floating IP Address' -f value )

이것은명령 대체내부에 하나일반 변수 할당, 배열 할당이 아닙니다.모든 복합 배열 할당은 다음 형식을 갖습니다.x=( ... ), 아래에서 사용하는 것처럼. 여기에는 하위 쉘이 없습니다(단순히 대체 명령의 실행 컨텍스트 역할을 하는 것 제외).

명령 대체를 사용하면 해당 내용이 포함된 변수가 해당 위치에서 작동하는 것과 동일한 방식으로 작동하므로 float=$x여기서는 유사하지만 ls $x또는 와도 유사합니다 foo=($x).분사확장된 결과에 대해 수행되며 변수의 모든 문자에서 값을 별도의 인수로 분할합니다 IFS.

인용 확장을 통해 단어 분리를 억제할 수 있습니다 "$(...)".

분할된 단어의 배열을 생성하려면 다음이 필요합니다.둘 다배열을 만들고 분할이라는 단어를 얻습니다. 이는 두 번째 경우와 같이 foo=(...)매개변수 또는 명령 대체와 $...결합된 배열 할당을 의미합니다.

float=( $( openstack floating ip list -c 'Floating IP Address' -f value ) )

float=(...)명령 대체 중에 수행된 토큰화에서 요소를 가져온 배열을 만듭니다 $(...).


혼란스러울 수 있는 점은 배열이 아닌 항목을 배열로 사용할 때 Bash가 자동으로 이를 싱글톤 배열로 변환하므로 배열을 얻는 것처럼 보이지만 항목은 하나라는 것입니다.

echo ${float[0]}
echo ${#float[@]}

이것은아주 똑똑하게 녹음했어:

유효한 첨자를 사용한 변수에 대한 참조는 모두 유효하며, 필요한 경우 bash는 배열을 생성합니다.

다른 색인을 사용하면 이를 더 명확하게 볼 수 있습니다.

float[1]=abc
echo ${#float[@]} # => 2

변환 프로세스에서는 변수의 기존 값(있는 경우)만 배열의 인덱스 0에 있는 항목으로 사용합니다.

답변3

괄호는 var=( some things )하위 쉘을 표시하지 않습니다.배열 할당 구문. 따라서 그것들이 없으면 일반(스칼라) 변수에 할당됩니다. 일반 할당의 오른쪽은 토큰화되지 않으므로 문자열 이 var=$(echo foo bar)에 들어가고 공백이 추가됩니다. 반면에 배열 할당에는 여러 단어가 필요하므로 두 단어 모두 2요소 배열을 제공합니다 .foo barvararr=(foo bar)arr=( $(echo foo bar) )

관련 정보