다음 쉘 스크립트 함수를 고려하십시오.
#!/bin/bash
declare -a dir
function() {
local -a directories=( "A/B/C D" "E/F G H" ) #Initialize local array.
printf "%q " "${directories[@]}" #"Return" values of array in escaped form.
}
dir=( $(funcion) )
for i in "${dir[@]}"; do
echo $i
done
명령 대체가 작동하는 방법:
dir=( A/B/C\ D E/F\ G\ H ) #Escape the whitespace.
스크립트의 결과는 다음과 같아야 합니다.
A/B/C D
E/F G H
명령 대체가 실제로 작동하는 방식(결과 때문에 그렇게 생각합니다):
dir=( A/B/C\\ D E/F\\ G\\ H ) #Escape the backslash.
스크립트의 결과는 다음과 같습니다.
A/B/C\
D
E/F\
G\
H
나처럼 작동하게 하는 방법이 없을까?
답변1
내 생각에는 당신 \n
이 printf
이것을 가지고 있습니다.
$ directories=( "A/B/C D" "E/F G H" )
$ printf "%q " "${directories[@]}"
이는 다음을 효과적으로 평가합니다.
$ printf "%q " "A/B/C D" "E/F G H"
A/B/C\ D E/F\ G\ H
이로 인해 for 루프가 A/B/C\
, D
, E/F\
및 G\
를 반복하게 됩니다 H
.
대신 다음을 사용하는 경우 "%q\n"
:
$ printf "%q\n" "${directories[@]}"
A/B/C\ D
E/F\ G\ H
그런 다음 다음을 사용하여 결과( 에서 온다고 가정 func
)를 배열로 읽을 수 있습니다.
readarray -t dir < <(func)
답변2
directories=( "A/B/C D" "E/F G H" ) #Initialize local array. printf "%q " "${directories[@]}"
그러면 출력이 쉘 입력으로 사용하기에 적합하도록 인용된 값이 인쇄됩니다.
dir=( $(func) )
그러면 출력이 얻어지고 func
, 토큰화 및 와일드카드를 통해 실행되고, 결과 필드가 배열에 저장됩니다.
호환되는 형식이 아닙니다. 특히 후자는 획득한 데이터를 다음과 같이 처리합니다.데이터, 따옴표, 이스케이프, 연산자 등과 같은 쉘 구문을 구문 분석하지 않습니다. 공백만 보입니다. (데이터의 백슬래시는 벗어날 수 없습니다. 애초에 특별한 의미가 없습니다.)
입력을 쉘 구문으로 처리하려면 를 통해 실행해야 eval
하지만 이는 다른 것도 실행된다는 단점이 있습니다. 예를 들어 내장된 명령 대체가 실행됩니다(생각해 보세요 $(reboot)
).
더 나은 접근 방식은 처음부터 데이터를 셸 구문으로 변환하지 않는 것입니다. 대신, 적절한 문자를 종결자로 사용하여 배열 값을 인쇄하고 프로세스 대체 read
를 사용하여 readarray
다시 읽습니다 .
예를 들어 개행 구분 기호를 사용하면 다음과 같습니다.
f() {
printf "%s\n" "hello world" 'some"quotes\etc'
}
readarray -t arr < <(f)
또는 NUL 문자를 구분 기호로 사용하여 값에 개행 문자를 포함할 수 있습니다.
g() {
printf "%s\0" "hello world" 'some"quotes\etc' $'two\nlines\n'
}
readarray -d '' -t arr < <(g)
(그런데 Bash에는 키워드가 있기 function() ...
때문에 작동하지 않습니다 . 그러나 Dash와 Busybox에서는 작동하지만 배열에서는 작동하지 않습니다.)function