다음 예가 있습니다.
#!/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
쉘은 공백이 단어 구분 기호인 자체 구문으로 행을 구문 분석하고 , cmd1
및 cmd
인수 로 arg1
호출 됩니다.arg2
노트: cmd
인수에 공백 문자를 허용하지 않습니다. 공백은 쉘 언어 구문의 연산자일 뿐입니다.
C와 마찬가지로 func("foo", "bar")
런타임에 두 개의 포인터 인수를 받아 작성하면 또는 또는 공백 문자가 func
표시되지 않습니다 .(
,
"
쉘 구문의 일부도 인용됩니다. "
쉘 구문의 다른 부분을 포함하는 문자를 포함할 수 있는 단어에 사용됩니다.
이 작업을 수행할 때:
cmd "arg 1" arg2
cmd
cmd
, arg 1
및 arg2
인수를 받습니다 . 아무런 문자도 보이지 않습니다 "
. 이는 "
쉘 구문에서 공백이 단어 구분 기호로 처리되는 것을 방지하는 데 사용됩니다.
이제 이렇게 하면:
cmd $VAR
이는 다음을 수행하는 것과 다릅니다.
cmd the content of the variable
그렇다면 문제가 발생합니다.
VAR='foo; reboot'
echo $VAR
예를 들어.
Bourne과 같은 쉘에서는 의 내용이 어느 $VAR
쪽에도 단일 인수로 축어적으로 전달되지 않습니다 (불행히도 이 문제는 , 및 그보다 덜한 cmd
일부 다른 쉘에서는 수정되었습니다 ). rc
대신 분할 및 와일드카드( )가 적용되고 결과 단어가 에 전달됩니다.es
fish
zsh
split+glob
cmd
$IFS
분할은 기본적으로 공백, 탭 및 줄 바꿈을 사용하는 특수 변수의 문자를 기반으로 합니다 .
$ARGUMENTS
포함된 내용 에 대해서는 , , 로 -executors 1 -description "The Host"
구분됩니다 . 이러한 단어에는 와일드카드가 포함되어 있지 않으므로 glob 부분이 적용되지 않으므로 이러한 단어는 에 전달됩니다 .-executors
1
-description
"The
Host"
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
하나로 유지됩니다.단어공백이 포함된 경우에도 마찬가지입니다.