무엇을 해야 할까요?

무엇을 해야 할까요?

저는 몇 가지 다른 매개변수를 사용하여 명령(궁금하신 경우 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[@]}"
)

관련 정보