인용된 매개변수를 전달하기 위해 eval을 사용해야 하는 이유는 무엇입니까?

인용된 매개변수를 전달하기 위해 eval을 사용해야 하는 이유는 무엇입니까?

다음 예가 있습니다.

#!/bin/bash
ARGUMENTS="-executors 1 -description \"The Host\" "

# call1
# error: parameter Host" is not allowed
java -jar swarm-client.jar $ARGUMENTS

# call2    
# works fine with eval
eval java -jar swarm-client.jar $ARGUMENTS

에서 $ARGUMENTS나는 주장을 인용합니다. 인용 문제를 해결해야 하는 call1이유를 이해할 수 없습니다 .eval

쉘에서 명령 평가의 프로세스와 순서를 이해하지 못하는 것 같습니다. 나에게 설명해 주실 수 있나요?

답변1

당신은하지 않습니다인용된 인수 전달명령의 경우 인수를 전달할 수 있습니다.

입력할 때:

cmd arg1 arg2

쉘은 공백이 단어 구분 기호인 자체 구문으로 행을 구문 분석하고 , cmd1cmd인수 로 arg1호출 됩니다.arg2

노트: cmd인수에 공백 문자를 허용하지 않습니다. 공백은 쉘 언어 구문의 연산자일 뿐입니다.

C와 마찬가지로 func("foo", "bar")런타임에 두 개의 포인터 인수를 받아 작성하면 또는 또는 공백 문자가 func표시되지 않습니다 .(,"

쉘 구문의 일부도 인용됩니다. "쉘 구문의 다른 부분을 포함하는 문자를 포함할 수 있는 단어에 사용됩니다.

이 작업을 수행할 때:

cmd "arg 1" arg2

cmdcmd, arg 1arg2인수를 받습니다 . 아무런 문자도 보이지 않습니다 ". 이는 "쉘 구문에서 공백이 단어 구분 기호로 처리되는 것을 방지하는 데 사용됩니다.

이제 이렇게 하면:

cmd $VAR

이는 다음을 수행하는 것과 다릅니다.

cmd the content of the variable

그렇다면 문제가 발생합니다.

VAR='foo; reboot'
echo $VAR

예를 들어.

Bourne과 같은 쉘에서는 의 내용이 어느 $VAR쪽에도 단일 인수로 축어적으로 전달되지 않습니다 (불행히도 이 문제는 , 및 그보다 덜한 cmd일부 다른 쉘에서는 수정되었습니다 ). rc대신 분할 및 와일드카드( )가 적용되고 결과 단어가 에 전달됩니다.esfishzshsplit+globcmd

$IFS분할은 기본적으로 공백, 탭 및 줄 바꿈을 사용하는 특수 변수의 문자를 기반으로 합니다 .

$ARGUMENTS포함된 내용 에 대해서는 , , 로 -executors 1 -description "The Host"구분됩니다 . 이러한 단어에는 와일드카드가 포함되어 있지 않으므로 glob 부분이 적용되지 않으므로 이러한 단어는 에 전달됩니다 .-executors1-description"TheHost"cmd

여기에서는 연산자를 사용 split+glob하고 해당 단어에 표시되지 않는 문자를 구분 기호로 사용하여 부분을 분할할 수 있습니다.

ARGUMENTS='-executors|1|-description|The Host'
IFS='|'
cmd $ARGUMENTS

또는 이를 지원하는 쉘(예 bash: )의 경우 더 좋습니다.배열 사용, 이러한 매개변수를 모두 포함하는 변수를 포함할 수 있습니다.

eval쉘 코드를 평가하는 것입니다. 따라서 또 다른 옵션은 ARGUMENTS셸 코드(인수 목록이 아닌 셸 구문의 텍스트)를 포함 하고 이를 eval해석에 전달하는 것입니다. 하지만 분할+글로브 연산자를 피하기 위해 변수를 인용하는 것을 기억하세요.

eval "cmd $ARGUMENTS"

답변2

따옴표가 다른 문자열 안에 있으면 bash는 이를 다른 문자로 처리합니다. 대신 배열을 사용하십시오.

args=(-executors 1 -description "The Host")
java -jar swarm-client.jar "${args[@]}"

이 문제에 대한 자세한 논의는 다음을 참조하세요."명령을 변수에 넣으려고 하는데 복잡한 경우가 항상 실패합니다!".

또한 변수 이름에는 소문자 또는 대소문자가 혼합된 이름을 사용하십시오. 시스템은 변수 이름에 모두 대문자를 사용하므로 실수로 그 중 하나를 덮어쓰는 것을 원하지 않습니다.

어떻게 작동하나요?

배열이 정의되면 args따옴표로 묶인 개별 문자열이 배열의 개별 항목이 됩니다. 다음을 사용하여 배열의 내용을 검사하면 declare -p arrayname이를 확인할 수 있습니다.

$ args=(-executors 1 -description "The Host")
$ declare -p args
declare -a args=([0]="-executors" [1]="1" [2]="-description" [3]="The Host")

보시다시피 문자열은 The Host배열의 요소 3입니다.

Bash가 특수 형식을 확장하면 "${args[@]}"배열의 각 요소가 별도의 요소가 됩니다.단어. 이렇게 하면 문자열이 The Host하나로 유지됩니다.단어공백이 포함된 경우에도 마찬가지입니다.

관련 정보