ssh localhost sh -c 'echo "$0"' arg0이 아무것도 출력하지 않는 이유는 무엇입니까?

ssh localhost sh -c 'echo "$0"' arg0이 아무것도 출력하지 않는 이유는 무엇입니까?

~처럼echo가 /bin/sh -c echo foo라고 불리며 아무것도 출력하지 않는 이유는 무엇입니까?하지만 ssh.

왜 아무것도 출력되지 않습니까?

ssh localhost sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3

하지만 내가 그것을 다음과 같이 바꾸면

ssh localhost sh -c 'true; echo "0=$0 1=$1"' arg1 arg2 arg3
# Output is
0=bash 1= arg1 arg2 arg3

내가 보고 있는 동작은 echo 명령이 실행 중이지만 변수 대체가 예상대로 작동하지 않음을 나타냅니다. 바라보다https://unix.stackexchange.com/a/253424/119816

SSH 없이 실행하면 예상대로 작동합니다.

위와 동일하지만 ssh 명령을 제거했습니다.

sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3
# Output is
0=arg1 1=arg2

# Adding true gives same output
sh -c 'true; echo "0=$0 1=$1"' arg1 arg2 arg3
0=arg1 1=arg2

한 시스템에서 다른 시스템으로 루트 액세스 가능 파일을 복사하려고 합니다.

ssh 명령을 사용하여 루트 파일을 다른 시스템에 복사하려고 합니다. 내가 시도하는 명령은 다음과 같습니다

file=/etc/hosts
set -x
ssh host1 sudo cat $file | ssh host2 sudo sh -c 'exec cat "$0"' $file
# Output is
+ ssh host2 sudo sh -c 'exec cat > "$0"' /etc/hosts
+ ssh host1 sudo cat /etc/hosts
bash: : No such file or directory

제 눈에는 괜찮아 보이지만 문제를 해결하는 방법을 모르겠습니다.

내 솔루션

내 해결책은 이전에 사용했던 것으로 돌아가는 것이었습니다.

ssh host1 sudo cat $file | ssh host2 sudo tee $file > /dev/null

위의 내용은 유효합니다.

해결책을 찾기

나는 이 문제에 직면하여 다음과 같은 질문을 했습니다.

다른 사람들은 다음 명령에 문제/질문이 있습니다 sh -c.

그러나 ssh를 사용할 때 추가적인 쉘 평가가 발생하는 미묘한 상황이 발생해야 합니다.

답변1

이것은 귀하가 언급한 것과 동일한 문제입니다. 로컬 셸은 한 레이어의 따옴표를 제거합니다. 이게 무슨 일이야

초기 코드

ssh localhost sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3

로컬 셸 확장 후, 명령 실행 전

ssh localhost sh -c echo "0=$0 1=$1" arg1 arg2 arg3
#                   ^^^^^^^^^^^^^^^^ a single token
#             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ passed to the remote shell

셸 확장 후 실행 전 원격 셸에서

sh -c echo 0= 1= arg1 arg2 arg3
#          ^^^^^ a single token
#     ^^^^ argument for -c

gets는 실행할 명령으로 echo바인딩되고 나머지는 매개변수입니다.sh -c

빈 줄이 나타나야 합니다.

개인적으로 저는 ssh해당 인수를 원격 셸에 직접 전달하는 방법을 배웠으며 원격 셸에서 실행됩니다. 그래서 나는 실행을 위해 해당 부분이 그대로 원격 셸에 전달된다는 점을 ssh상기시키는 이와 같은 명령을 작성하는 경향이 있습니다.some command line…제가 직접 입력한 것처럼:

ssh remoteHost 'some command line…'

(로컬 평가를 방지하려면 줄을 작은따옴표로 묶거나, 로컬 변수를 삽입하려면 큰따옴표를 사용하세요.)


그런 다음 실제로 루트 파일을 다른 시스템에 복사하기 위해 ssh 명령을 얻으려고 한다고 말합니다.

file=/etc/hosts
ssh -n host1 "scp -p '$file' host2:'/path/to/destination'"

또는 파일 이름은 안전하고 로컬 클라이언트와 host1from to host1사이에 루트 동등성이 있다고 가정합니다 host2.

ssh -n root@host1 scp -p /etc/hosts host2:/etc/hosts

현대적인 것은 scp더욱 단순화될 수 있습니다:

scp -OR -p root@host1:/etc/hosts root@host2:/etc/

답변2

-v명령에 추가하면 ssh수행 중인 작업이 표시됩니다.

debug1: Sending command: sh -c echo "0=$0 1=$1" arg1 arg2 arg3

물론, 명령을 로컬에서 실행하면 실행 후 0번째 인수가 된 sh이후 빈 출력 줄만 얻게 됩니다 .shecho"0=$0 1=$1"

앞에 다음을 추가하면 true;이런 일이 발생합니다 .

debug1: Sending command: sh -c true; echo "0=$0 1=$1" arg1 arg2 arg3

이제 sh실행해 보세요 true. 그런 다음 echo해당 매개변수를 출력합니다.

0=bash 1= arg1 arg2 arg3

sh -c 'echo "0=$0 1=$1"' arg1 arg2 arg3아마도 당신이 원하는 것은 반대편 으로 달려가는 것입니다 . 원격 셸이 전체 명령을 수신하도록 전체 명령을 인용해야 합니다.

ssh localhost "sh -c 'echo \"0=\$0 1=\$1\"' arg1 arg2 arg3"

산출:

0=arg1 1=arg2

printf로컬 측에 GNU가 있는 경우 이를 사용하여 원격 측에 맞게 형식을 지정하면 명령 문자열을 더 읽기 쉽게 만들 수 있습니다.

command='echo "0=$0 1=$1"'
ssh localhost "sh -c $(printf %q "$command") arg1 arg2 arg3"

관련 정보