저는 몇 가지 다른 매개변수를 사용하여 명령(궁금하신 경우 weka)을 몇 번 호출하는 스크립트를 작성하고 있습니다. 매개변수 중 하나를 '-search "< stuff >" '
인용해야 합니다. 어떤 경우에는 이러한 매개변수를 여러 개 사용해야 합니다.
weka a -search "a params" -search "other a params"
weka b -search "just these params"`
나는 다음과 같은 연관 배열을 사용하려고 노력해 왔습니다.
search=( ["a"]='-search "a params" -search "other a params"'
["b"]='-search "just these params"'
그런 다음 전화를 겁니다.
function call_thing_with_the_right_parameters_so_it_works_out_alright {
weka $1 ${search["$1"]}
} # <-- closing brace for the function
call_thing_with_the_right_parameters_so_it_works_out_alright
아아, 내가 무엇을 하려고 해도 인용문이 엉망이 되었습니다.
bash -x ./this_is_the_name_of_my_script_sorry_its_so_long
...
+ weka a -search '"a' 'params"' # <-- (not what I want)
...
어떤 아이디어가 있나요?
답변1
코드 줄은 weka $1 ${search["$1"]}
쉘 분할의 영향을 받습니다.
변수를 변경하지 않으면 $IFS
분할이 에서 발생합니다 spacetabnew line.
라인은 다음으로 확장됩니다.
weka $1 ${search["$1"]}
weka a -search "a params" -search "other a params"
그러나 위와 같이 분할하면 다음과 같은 의미가 됩니다.
<weka> <a> <-search> <"a> <params"> <-search> <"other> <a> <params">
줄 앞에 정확히 동일한 printf가 추가된 것을 볼 수 있습니다.
$ printf '<%s> ' weka $1 ${search["$1"]}; echo
<weka> <a> <-search> <"a> <params"> <-search> <"other> <a> <params">
변수가 올바르게 인용되면 상황이 더 좋아질 것입니다.
$ printf '<%s> ' weka "$1" "${search["$1"]}"; echo
<weka> <a> <-search "a params" -search "other a params">
그러나 그것은 당신이 원하는 것이 아닙니다. 분할해야 하지만 단순히 공간만 분할하면 안 됩니다.
무엇을 해야 할까요?
두 가지 솔루션이 있습니다.
수동 분할
일부 문자를 사용하여 #
분할 위치를 수동으로 표시하십시오.
search=( ["a"]='-search#a params#-search#other a params' ["b"]='-search#just these params' )
IFS
그런 다음 문자열을 새 배열로 분할할 수 있도록 분할하는 데 사용한 문자를 bash에 알려줍니다 b
.
IFS='#'
b=( ${search["a"]} )
printf '<%s> ' "${b[@]}"; echo
다음을 생성합니다.
<-search> <a params> <-search> <other a params>
원하는 정확한 분할.
유일한 문제는 IFS
변경되었다는 점이지만 로컬 함수에서 이 문제를 해결할 수 있습니다 IFS
.
callsplit(){
local IFS='#'
b=( ${search["$1"]} )
weka "$1" "${b[@]}"
}
사용평가
또 다른 해결책은 쉘이 라인을 분할하는 일반적인 방법과 마찬가지로 쉘이 명령줄을 분할할 수 있도록 eval을 사용하여 명령줄을 재분석하는 것입니다.
변수 검색의 값은 정의한 대로입니다.
search=( ["a"]='-search "a params" -search "other a params"'
["b"]='-search "just these params"' )
하지만 eval을 사용하여 실행 라인을 확장하겠습니다.
eval weka "$1" "${search["$1"]}"
줄이 어떻게 확장되는지 보려면 다음 명령을 사용하십시오.
$ eval printf "'<%s> '" weka "$1" "${search["$1"]}"; echo
<weka> <a> <-search> <a params> <-search> <other a params>
전체 스크립트는 다음과 같습니다:
#!/bin/bash
declare -A search
search+=( ["a"]='-search "a params" -search "other a params"')
search+=( ["b"]='-search "just these params"' )
call_thing() {
eval weka "$1" "${search["$1"]}"
} # <-- closing brace for the function
call_thing "a"
참고: 검색 값이 설정되어 있다고 가정하면 제대로 작동합니다.~에스크립트(외부 공격자는 설정할 수 없음) 및 값은 일반 쉘 "명령줄"로 참조됩니다.
경고하다: eval을 사용하면 문자열 형식의 데이터를 명령과 유사한 코드로 변환할 수 있습니다. 이 특정 스크립트에서 다음 줄은 다음과 같습니다.
call_thing "a; touch new_file"
명령이 실행됩니다 touch new_file
. 그러나 다른 명령도 실행할 수 있습니다. 먹이는 것에 주의하고 매우 조심하십시오 eval
.
위에서 언급한 것처럼 셸에서 실행할 수 있는 위험한 명령이 많이 있다는 점을 기억하세요 rm -r /
. 이 명령은 eval
어떤 명령보다 강력하지 않습니다. 조심하시기 바랍니다.
답변2
쉘은 원하는 방식으로 따옴표를 처리하지 않습니다. (따옴표를 한 번 인용하면 일반 문자로 처리됩니다.)
bash를 속여 원하는 작업을 수행할 수 있습니다. 연관 배열 정의를 시작하려면 다음을 수행하십시오.
declare -A s
s=( ["a"]='-search;a params;-search;other a params;' ["b"]='-search;just these params' )
보시다시피 문자열에는 세미콜론으로 구분된 각 명령의 인수가 포함되어 있습니다. 예를 들어, 에 대한 인수를 추출하려면 이를 필드 구분 기호 a
로 사용하도록 쉘에 지시합니다 .;
IFS=\; v=(${s[a]})
v
이제 배열에 다음과 같은 필수 필드가 있는지 확인할 수 있습니다 .
$ declare -p v
declare -a v='([0]="-search" [1]="a params" [2]="-search" [3]="other a params")'
그런 다음 다음과 같이 실행할 수 있습니다 weka
.
weka a "${v[@]}"
따라서 모든 것을 종합하면 함수 정의는 다음과 같습니다.
declare -A s
s=( ["a"]='-search;a params;-search;other a params;' ["b"]='-search;just these params' )
callthing() (
IFS=\; v=(${s[$1]})
weka "$1" "${v[@]}"
)