다음과 같은 문자열이 있습니다.
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
나는 이것을 다음과 같이 나눌 수 있기를 원합니다.
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
어떻게 해야 하나요? (바람직하게는 단일 라이너 사용)
답변1
David Postill의 답변을 보고 "분명 더 간단한 해결책이 있을 것"이라고 생각했습니다. 몇 가지 실험 끝에 다음 작품을 발견했습니다.
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo $string
eval 'for word in '$string'; do echo $word; done'
이는 결과 줄(인라인 답변)을 실행하기 전에 eval
줄을 확장(따옴표 제거 및 확장 ) 하기 때문에 작동합니다 .string
for word in "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"; do echo $word; done
동일한 라인으로 확장되는 대안은 다음과 같습니다.
eval "for word in $string; do echo \$word; done"
여기서는 string
큰따옴표 내에서 확장되지만 줄이 실행되기 전에 확장되지 않도록 $
이스케이프해야 합니다 word
(다른 형식에서는 작은따옴표를 사용해도 동일한 효과가 있습니다). 결과는 다음과 같습니다:-
[~/]$ string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
[~/]$ echo $string
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
[~/]$ eval 'for word in '$string'; do echo $word; done'
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
[~/]$ eval "for word in $string; do echo \$word; done"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
답변2
가장 간단한 해결책은 인용된 인수의 배열을 만드는 것입니다. 그런 다음 원할 경우 반복하거나 명령에 직접 전달할 수 있습니다.
eval "array=($string)"
for arg in "${array[@]}"; do echo "$arg"; done
ps. 가 없는 더 간단한 방법을 찾으면 댓글을 달아주세요 eval
.
편집하다:
@Hubbitus의 답변을 토대로 완전히 삭제되고 적절하게 인용된 버전이 있습니다. 참고: 이는 과잉이며 실제로 대부분의 구두점 앞에 큰따옴표 또는 작은따옴표 섹션에 추가 백슬래시를 남기지만 공격에 취약하지 않습니다.
declare -a "array=($( echo "$string" | sed 's/[][`~!@#$%^&*():;<>.,?/\|{}=+-]/\\&/g' ))"
관심 있는 독자에게 적합하다고 판단되는 대로 수정하도록 맡깁니다.http://ideone.com/FUTHhj
답변3
xargs가 꽤 잘 할 수 있는 것 같습니다:
$ a='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
$ printf "%s" "$a" | xargs -n 1 printf "%s\n"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
답변4
declare
예를 들어 다음과 같이 대신 을 사용하여 수행할 수 있습니다 eval
.
대신에:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo "Initial string: $string"
eval 'for word in '$string'; do echo $word; done'
하다:
declare -a "array=($string)"
for item in "${array[@]}"; do echo "[$item]"; done
그러나 사용자로부터 입력을 받는 경우에는 그다지 안전하지 않습니다.
따라서 다음과 같은 문자열을 사용하여 시도해 보면:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
당신은 평가를 받습니다 hostname
(물론 와 같은 것이 있을 수도 있습니다 rm -rf /
)!
이를 보호하기 위한 매우 간단한 시도는 백트릭 ` 및 $와 같은 문자를 대체하는 것입니다.
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
declare -a "array=( $(echo $string | tr '`$<>' '????') )"
for item in "${array[@]}"; do echo "[$item]"; done
이제 다음과 같은 출력을 얻었습니다.
[aString that may haveSpaces IN IT]
[bar]
[foo]
[bamboo]
[bam boo]
[?hostname?]
좋은 답변에서 찾을 수 있는 방법과 장단점에 대한 자세한 내용은 다음과 같습니다.https://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead/17529221#17529221
하지만 여전히 공격할 수 있는 경로가 남아 있습니다. 나는 큰 따옴표 (")와 같은 문자열 따옴표의 bash 방법을 원하지만 내용을 해석하지 않고 싶습니다..