Bash: 공백과 따옴표가 있는 문자열을 배열로 변환

Bash: 공백과 따옴표가 있는 문자열을 배열로 변환

따옴표 안에 일련의 문자열을 출력하는 함수(내가 만든 것이 아님)가 있습니다.

command <args>

“Foo”
“FooBar”
“Foo Bar”
“FooBar/Foo Bar”

배열(Bash, BSD/Mac)에 할당하려고 하면 4개가 아닌 7개의 요소가 표시됩니다. 예를 들어, ${array[2]}나 에게~해야 한다get 이지만 대신 “Foo Bar”내가 얻는 ”Foo다음 요소 는 Bar”.any 요소 입니다.아니요공백은 잘 작동합니다(예 ${array[0]}: "Foo")

요소 자체가 공백(?)으로 구분되는 배열에 따옴표(공백 포함) 사이의 각 요소를 할당하는 방법은 무엇입니까?

이제 sed/awk를 사용하여 따옴표를 "제거"하는 것을 고려하고 있지만 더 좋고 효율적인 방법이 있어야 한다고 생각합니다.

현재 저는 명령의 출력(따옴표를 포함하여 위의 출력과 정확히 동일함)을 임시 변수에 할당한 다음 이를 배열에 할당합니다.

_tempvar=“$(command <args>)”

declare -a _array=(${_tempvar})

답변1

에서는 파일의 행이나 일부 명령의 출력을 배열로 읽을 bash수 있습니다 .readarray오직 이 기능은 2009년에 출시된 버전 4.0에 추가되었지만 macOS는 여전히 bash 3.2와 함께 제공됩니다.

macos는 zsh와 함께 제공되지만 이것이 더 나은 쉘입니다.

비어 있지 않은 명령 출력 줄을 얻으려면 f인수 확장 플래그를 사용하여 f분할 하고( eed 줄에서 분할) 연산자 기호 를 사용하여 "(U+0022), (U+0201C) 및 (U+ 201D) 문자를 제거할 수 있습니다. ${var//pattern[/replacement]}와 같은:

#! /bin/zsh -
array=( ${(f)${"$(cmd)"//['"“”']}} ) || exit

U+0022 ASCII 문자로 인용된 문자열이고 인용문이 언어에서 인용문이 작동하는 방식과 호환되는 경우 / 플래그(언어 구문 분석기와 동일한 방식으로 텍스트를 표시하기 위해) 및 플래그를 zsh사용할 수도 있습니다. (따옴표를 제거하기 위해) 한 줄로 나누는 대신(따옴표 붙은 문자열이 여러 줄에 걸쳐 있을 수 없다고 가정)zZQ

#! /bin/zsh -
array=( ${(Q)${(Z[n])"$(cmd)"}} ) || exit

당신의

declare -a array=(${tempvar})

in은 bash따옴표가 없는(보통 의도하지 않게) 확장될 때 호출되는 분할+glob 연산자를 사용합니다. 복잡한 알고리즘을 사용하여 출력을 $IFS특수 매개변수의 문자(bash에서는 기본적으로 공백, 탭 및 개행 문자 포함)로 분할하고 결과 단어는 다음과 같습니다.와일드카드또한 ~으로 알려진파일 이름 생성(이것은 거의 바람직하지 않습니다).

여기서는 분할+glob을 사용하여 명령 출력의 비어 있지 않은 줄을 가져올 수 있지만 먼저 이를 조정해야 합니다.

IFS=$'\n' # split on newline only:
set -o noglob # disable the glob part which we don't want
array=( $(cmd) ) # split+glob

"“”그런 다음 with 를 제거할 수도 있지만 ${var//pattern[/replacement]}bash에서는 인수 확산 연산자를 누적할 수 없고 구문(ksh93에서 상속됨)이 약간 어색하기 때문에 나중에 수행해야 합니다.

array=( "${array[@]//['"“”']}" )

이 방법과 달리 zsh다음과 같은 작업은 처리하지 않습니다 "foo \"bar\" and \\backslash".

답변2

공백으로 인해 토큰화가 발생하므로 7개의 요소를 얻습니다.

IFS=$'\n'문자열을 배열에 추가하기 전에 설정하면 4개의 요소가 표시되지만 큰따옴표가 포함됩니다.

예:

IFS=$'\n'

arr=($(command <args>))

따옴표 없이 4개의 요소를 원하는 경우 다음을 수행하십시오.

IFS=$'\n'

arr=($(command <args> | sed s'#"##'g))

완전한 예:

IFS=$'\n'

# tst.txt has your strings:
arr=($(cat tst.txt | sed s'#"##'g))

declare -p arr

산출:

declare -a arr=([0]="Foo" [1]="FooBar" [2]="Foo Bar" [3]="FooBar/Foo Bar")

답변3

readarray -t array <<< $(echo $'"a a"\n"b   b"\n"c   c"')
declare -p array
declare -a array=([0]="\"a a\"" [1]="\"b   b\"" [2]="\"c   c\"")
readarray -t array <<< $(command <args>)

관련 정보