Bash 스크립트가 예상대로 변수를 대체하지 않습니다.

Bash 스크립트가 예상대로 변수를 대체하지 않습니다.

jmxquery라는 명령을 사용하는 쉘 스크립트를 작성하려고 합니다.

이는 명령줄에서 작동합니다.

[root@monitor jmxquery]# java -jar /opt/jmxquery/jmxquery.jar \
    -U service:jmx:rmi:///jndi/rmi://tomcat.cyberdyne.corp:1099/jmxrmi \
    -O java.lang:type=GarbageCollector,name='PS MarkSweep' \
    -A LastGcInfo \
    -K GcThreadCount

**JMX OK - LastGcInfo.GcThreadCount=4 | LastGcInfo.GcThreadCount=4**

보시다시피, 스레드 개수 세부정보로 JMX OK를 얻었습니다. 그래서 쉘 스크립트에서 동일한 작업을 수행하려고 합니다. 다음과 같이 정의된 변수가 있습니다.

JAR=/opt/jmxquery/jmxquery.jar
JMXHOST=tomcat.cyberdyne.corp
JMXPORT=1099
SERVICE_URL="service:jmx:rmi:///jndi/rmi://${JMXHOST}:${JMXPORT}/jmxrmi"
attr_marksweep_threadcount="-O java.lang:type=GarbageCollector,name='PS MarkSweep' -A LastGcInfo -K GcThreadCount"

그런 다음 다음을 실행합니다.

java -jar ${JAR} -U ${SERVICE_URL} $attr_marksweep_threadcount

이것은 bash -x 출력의 일부입니다.

+ attr_marksweep_threadcount='-O java.lang:type=GarbageCollector,name='\''PS MarkSweep'\'' -A LastGcInfo -K GcThreadCount'
+ java -jar /opt/jmxquery/jmxquery.jar -U service:jmx:rmi:///jndi/rmi://spotfirewin75.cyberdyne.corp:1099/jmxrmi -O 'java.lang:type=GarbageCollector,name='\''PS' 'MarkSweep'\''' -A LastGcInfo -K GcThreadCount
**JMX CRITICAL - java.lang:type=GarbageCollector,name='PS**

보시다시피 PS 이후의 나머지 명령은 잘렸습니다.

스크립트를 올바르게 바꾸려면 어떻게 해야 합니까?

답변1

이렇게 하면(주석에서 더 짧은 예를 다른 말로 표현):

mkdir "foo bar"
parms="-l 'foo bar'"
ls $parms

변수 parms분사공백과 함께 따옴표는 고려되지 않으므로 , -l, 'foo( bar'3개의 매개변수)가 됩니다. 원래 예제에는 와 동일한 문제가 있었는데 , 이는 다른 매개변수에서 참조되는 나머지 문자열을 attr_marksweep_threadcount포함하는 매개변수 중 하나로 끝났습니다 . java.lang:type=GarbageCollector,name='PS나는 당신의 자바가 이것을 좋아하지 않는다고 가정합니다.

매개변수가 포함된 변수를 참조하는 경우:

ls "$parms"

우리는 (논쟁) ls불려 졌습니다. -l 'foo bar'변수를 인용하면 단어 분할(파일 이름에 와일드카드 사용)을 방지할 수 있지만 인용 부호는~에변수는 그렇지 않습니다.

간단한 쉘 변수를 사용하여 이 문제를 해결하는 것은 다소 어렵지만 Bash는정렬, 하나를 사용하고 각 매개변수를 배열의 별도 요소에 넣을 수 있습니다.

array=("-l" "foo bar")
ls "${array[@]}"

"${array[@]}"모든 배열 멤버와 동등하게 확장됩니다(개별적으로 인용됨).


무제한의 쉘 배열의 경우 몇 가지 해결 방법을 사용해야 합니다. 이것위치 매개변수할 수 있다로 확장됨$@배열과 유사:

set -- "-l" "foo bar"
ls "$@"

또는 단어 분할은 에 설정된 문자에 따라서만 수행되므로 IFS공백이 아닌 다른 항목에서 쉘 분할을 만들 수 있습니다.

IFS=#
parms='-l#foo bar'
ls $parms
# though IFS stays set to the hash sign after this

예제의 출력은 bash -x진행 상황을 표시하려고 시도하지만 작은 따옴표 안에 작은 따옴표가 포함된 문자열을 표시하려고 하므로 출력이 약간 혼란스럽습니다. This: , 및 함께 연결된 모든 항목(작은따옴표로 묶인 두 개의 문자열과 작은따옴표로 묶인 작은따옴표) 'java.lang:type=GarbageCollector,name='\''PS' 으로 해석됩니다 . 큰따옴표를 사용하면 더 좋아 보입니다 .'java.lang:type=GarbageCollector,name='\''PS'"java.lang:type=GarbageCollector,name='PS"

답변2

교체해 보세요:

attr_marksweep_threadcount="-O java.lang:type=GarbageCollector,name='PS MarkSweep' -A LastGcInfo -K GcThreadCount"

그리고:

attr_marksweep_threadcount='-O java.lang:type=GarbageCollector,name="PS MarkSweep" -A LastGcInfo -K GcThreadCount'

관련 정보