이 답변의 대부분은 귀하가 요구하는 특정 사례에 부딪칩니다. 이 친구가 일반적인 접근 방식은 내가 임의 필요한 경우 인용을 허용하는 개발에 인용 bash는 명령 ssh를 통해 쉘 확장, 예를 들어, 여러 계층을 통해, su -c
, bash -c
, 하나 개의 코어 원시 여기 필요가있다 등 네이티브 배쉬에서 :
quote_args() {
local sq="'"
local dq='"'
local space=""
local arg
for arg; do
echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
space=" "
done
}
이것은 정확히 말한 것을 수행합니다 : 각 인수를 개별적으로 쉘 인용합니다 (물론 bash 확장 후).
$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'
하나의 확장 계층에 대해 분명한 작업을 수행합니다.
$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2
(큰 따옴표 $(quote_args ...)
는 결과를에 대한 단일 인수로 만들기 위해 필요합니다 bash -c
.) 더 일반적으로 여러 계층의 확장을 통해 적절하게 인용 할 수 있습니다.
$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2
위의 예 :
- 쉘은 각 인수를 내부에
quote_args
개별적 으로 인용 한 다음 결과를 내부의 큰 따옴표와 함께 단일 인수로 결합합니다.
- shell-quotes
bash
, -c
및 1 단계에서 이미 한 번 인용 된 결과를 찾은 다음 결과를 외부 큰 따옴표와 함께 단일 인수로 결합합니다.
- 그 혼란을 외부에 대한 논쟁으로 보낸다
bash -c
.
그것은 요컨대 아이디어입니다. 이것으로 꽤 복잡한 작업을 수행 할 수 있지만 평가 순서와 인용되는 하위 문자열에 대해주의해야합니다. 예를 들어, 다음은 잘못된 일을합니다 ( "잘못된"에 대한 일부 정의의 경우).
$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure
첫번째 예에서, 팽창 배시 즉시 quote_args cd /; pwd 1>&2
두 개의 명령어로, quote_args cd /
그리고 pwd 1>&2
CWD가 여전히 있으므로 /tmp
경우에 pwd
명령이 실행된다. 두 번째 예는 globbing과 비슷한 문제를 보여줍니다. 실제로 모든 bash 확장에서 동일한 기본 문제가 발생합니다. 여기서 문제는 명령 대체가 함수 호출이 아니라는 것입니다. 문자 그대로 하나의 bash 스크립트를 평가하고 다른 bash 스크립트의 일부로 출력을 사용하는 것입니다.
단순히 쉘 연산자를 이스케이프하려고하면 전달 된 결과 문자열 bash -c
이 개별적으로 인용 된 문자열 시퀀스이므로 연산자로 해석되지 않으므로 문자열을 에코하는지 쉽게 알 수 있습니다. bash로 전달되었습니다.
$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'
여기서 문제는 과다 인용하는 것입니다. 필요한 것은 연산자를 엔 클로징에 대한 입력으로 따옴표로 묶지 않는 것 bash -c
입니다. 즉, $(quote_args ...)
명령 대체 외부에 있어야합니다 .
결과적으로, 가장 일반적인 의미에서 수행해야 할 것은 명령 대체시 별도로 확장되지 않는 명령의 각 단어를 쉘 인용하고 쉘 연산자에 추가 인용을 적용하지 않는 것입니다.
$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success
이 작업을 마치면 임의의 수준의 평가에 더 인용하기 위해 전체 문자열이 공정합니다.
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success
기타
이러한 예는 과로 단어처럼 주어진 것처럼 보일 수 있습니다 success
, sbin
그리고 pwd
쉘 인용 할 필요는 없지만, 임의의 입력을 복용하는 스크립트를 작성할 때 키 포인트는 기억하면 당신이 절대적으로 확실하지 않은 모든 인용 할 것입니다 '아무튼를 t는 사용자가 던질 때 당신이 알고하지 않기 때문에, 인용 필요 Robert'; rm -rf /
.
표지 아래에서 무슨 일이 일어나고 있는지 더 잘 이해하기 위해 두 가지 작은 도우미 기능으로 놀 수 있습니다.
debug_args() {
for (( I=1; $I <= $#; I++ )); do
echo -n "$I:<${!I}> " 1>&2
done
echo 1>&2
}
debug_args_and_run() {
debug_args "$@"
"$@"
}
명령을 실행하기 전에 각 인수를 명령에 열거합니다.
$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2