SSH를 통해 `sh -c` 스크립트 실행(매개변수를 안전하고 정상적으로 전달)

SSH를 통해 `sh -c` 스크립트 실행(매개변수를 안전하고 정상적으로 전달)

SSH를 통해 이 작업을 수행하는 방법을 전혀 몰랐다는 사실이 떠올랐습니다.

나는 ~하려고 노력한다

$ ssh user@server sh -c 'echo "hello"'

그러나 아무것도 출력하지 않습니다. 오히려 빈 줄을 출력합니다. 주어진 명령이 ssh원격 호스트에서 실행되면 왜 이런 일이 발생하는지 이해할 수 있습니다(또는 스스로 합리화하려고 노력할 수 있습니다).$SHELL -c

좋습니다. 두 번째 시도입니다.

$ ssh user@server 'echo "hello"'
hello

모두 괜찮습니다.

이제 내가 정말로 원하는 것은:

$ ssh user@server 'echo "hello $1"' sh "world"
hello  sh world

흠... 어디서 나온 거야 sh? 이는 비어 있음을 나타내며 $1실제로 반대편에서 실행되는 것은 다음과 같습니다.

$SHELL -c 'echo "hello  sh world"'

내가 바라던 것 대신에,

$SHELL -c 'echo "hello $1"' sh "world"

ssh다음을 통해 실행되는 스크립트에 인수를 안전하게 전달하는 방법이 있습니까?

sh -c 'script text' sh "my arg1" "my arg2" "my arg3" ...

하지만 원격 호스트에서는요?

내 로컬 및 원격 로그인 쉘은 모두 /bin/sh.


안전 = 매개변수에 공백 등을 유지합니다.

Sanely = 따옴표를 미친 듯이 탈출하지 않습니다.

답변1

이 과정에서 가장 먼저 이해해야 할 것은 ssh가 매개변수를 처리하는 방법입니다. 실행하려는 매개변수가 아니라 ssh의 매개변수를 의미합니다. 를 호출하면 ssh원격 호스트 사양( ) 뒤에 오는 인수가 user@server연결되어 원격 측 셸을 통해 전달됩니다. 매개 변수가 로컬 측에서 올바르게 분할되었다고 해서 원격 측에서도 올바르게 분할된다는 의미는 아니기 때문에 주목할 가치가 있습니다.

귀하의 예를 사용하여 :

ssh user@server 'echo "hello $1"' sh "world"

이러한 매개변수는 명령으로 연결됩니다.

echo "hello $1" sh world

그게 네가 얻는 이유야

hello  sh world

hello및 사이의 이중 공백은 원래 있어야 할 곳이지만 그렇지 않기 sh때문입니다 .$1$1

 

가 없는 또 다른 예는 $1다음과 같습니다.

ssh user@server echo "foo      bar" baz

결과는 다음과 같습니다.

foo bar baz

이는 매개변수가 서로 연결되어 있으므로 다음 명령이 실행되기 때문입니다.

echo foo      bar baz

 

셸을 통해 전달된 명령을 우회할 수 있는 방법이 없기 때문에 전달한 내용이 셸 평가에서 살아남는지 확인하기만 하면 됩니다. 내가 보통 이것을 달성하는 방법은 다음과 같습니다printf "%q "

예를 들어:

cmd=(echo "foo      bar" baz)
ssh user@server "$(printf "%q " "${cmd[@]}")"

결과는 다음과 같습니다.

foo      bar baz

별도의 변수를 사용하는 것이 더 깔끔하고 이해하기 쉽지만 cmd필수는 아닙니다. 다음은 같은 방식으로 작동합니다.

ssh user@server "$(printf "%q " echo "foo      bar" baz)"

 

이는 쉘 매개변수 예에도 적용됩니다.

cmd=(sh -c 'echo 1="<$1>" 2="<$2>" 3="<$3>"' sh "my arg1" "my arg2" "my arg3")
ssh user@server "$(printf "%q " "${cmd[@]}")"

결과는 다음과 같습니다.

1=<my arg1> 2=<my arg2> 3=<my arg3>

 


대체 솔루션으로 명령을 완전한 셸 스크립트로 전달할 수 있습니다. 예를 들어:

ssh user@server <<'EOF'
sh -c 'echo 1="<$1>" 2="<$2>" 3="<$3>"' sh "my arg1" "my arg2" "my arg3"
EOF

그러나 이 솔루션에는 단점도 있습니다. 프로그래밍 방식으로 수행하는 것이 더 어렵기 때문입니다(STDIN을 통과하도록 문서 생성). 또한 STDIN을 사용하고 있기 때문에 원격 측의 스크립트가 STDIN을 읽도록 하려면 (적어도 약간의 트릭을 사용하면) 그렇게 할 수 없습니다.

관련 정보