
머신 A를 통해 머신 B에 연결하고 싶다고 가정해 보겠습니다. 제가 배운 대로 이를 달성하는 방법에는 여러 가지가 있습니다. 예를 들어
ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
# Some commands in machine B
END_OF_SSH_CONNECTION
또는
ssh -T user@machineA << END_OF_MACHINE_A
ssh -T machine B << END_OF_MACHINE_B
# Some commands in machine B
END_OF_MACHINE_B
END_OF_MACHINE_A
그러나 컴퓨터 B에 연결될 때 사용자가 명령을 입력할 수 있는 대화형 셸을 시작하는 방법은 명확하지 않습니다. 예를 들어 다음과 같이 작동합니다.
ssh user@machineA -t 'bash -l -c "bash"'
그리고 이것도 잘 작동합니다:
ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'
그러나 다음은 작동하지 않습니다.
ssh -J user@machineA user@machineB -t 'sudo apt-get update; bash -l -c "bash"'
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Connection to machineB closed.
그리고 다음도 마찬가지입니다.
ssh -J user@machineA user@machineB -t 'if [ 1 -eq 1 ]; then bash -l -c "bash"; fi'
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Connection to machineB closed.
나는 또한 이것을 시도했다:
ssh -T -J user@machineA user@machineB << EOF
# Some commands on machineB
# Check whether apache2 has been correctly installed
if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ];
then
printf "done\n";
else
printf "fail\nStarting an interactive shell: enter exit to quit\n";
bash -l -c "bash";
fi
EOF
이 마지막 버전은 거의 작동하지만(즉, 오류를 반환하지 않음) 사용자가 예상한 대로 명령을 입력할 수 있는 대화형 셸을 시작하지 않습니다.
누군가가 나를 도울 수 있기를 바랍니다. 미리 감사드립니다.
답변1
@attie 님, 도움을 주셔서 감사합니다. 귀하가 제안한 코드를 약간 수정했습니다. 아래에 보고하겠습니다.
#!/usr/bin/env bash ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF" if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then echo "done"; else echo "fail, starting an interactive shell"; bash -l -c "bash"; fi EOF ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
외부 파일에 쓸 필요도 없습니다.
#!/usr/bin/env bash
ssh -T -J user@machineA user@machineB << "EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q "ok installed"; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
EOF
기본적으로 field 확장 시도를 피하기 위해 사용된 따옴표가 누락되었습니다 ${Status}
.
답변2
원격 호스트에서 스크립트를 실행하려는 경우그리고대화형 쉘을 얻으면 두 가지 옵션이 있습니다.
- 전체 스크립트를 의 명령줄 인수에 넣습니다
ssh
. - 스크립트를 원격 호스트에 푸시한 다음(예:
scp
또는 사용ssh
) 실행합니다(예: 사용ssh
).
1. Args의 스크립트
마지막 예는 "긴"를 사용하면 가독성을 높이는 데 도움이 될 수 있습니다.mapfile
(에 내장되어 있음 bash
). "EOF"
확장하려는 시도를 피하기 위해 인용된 내용을 참고하세요 ${Status}
.
mapfile -t SCRIPT <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "${SCRIPT[@]}"
2. 스크립트를 푸시한 후 실행
mktemp
사용 후 청소에 대한 보너스 포인트 . "EOF"
다시 인용한 메모입니다 .
제공된 오류 메시지 중 하나(자세한 exec
내용은 아래 참조)에 따르면 이 사용은 cat >/tmp/myscript
아마도 제대로 작동하지 않을 것입니다.
ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
첫 번째 단계는 항상 문제를 가장 간단한 형태로 분해하는 것입니다. 마지막 주문인 경우 대신 다음을 시도해 보십시오.
ssh -T user@machineA << EOF
bash -l -c "bash";
EOF
무슨 일이야? 원격 호스트로부터 환영 메시지를 받지만 세션은 오류 없이 즉시 자동으로 종료됩니다.
변경 -T
(명시적으로장애를 입히다PTY 할당) -t
(PTY 할당 강제)은 올바른 방향에 대한 힌트를 제공합니다.
ssh -t user@machineA << EOF
bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.
stdin
이는 스크립트를 제공하는 데 사용하고 있으며 동일한 스크립트 stdin
(터미널이 아닌 파이프)를 원격 PTY에 연결하려고 시도하고 있음 을 나타냅니다 .
따라서 요소를 제거해 보겠습니다 stdin
.
ssh -t user@machineA bash -l -c "bash"
그리고 그것은 작동합니다!
근본적으로 당신은할 수 없다스크립트와 터미널 모두와 stdin을 공유합니다.
다른 오류의 경우:
E: Command line option 'l' [from -l] is not understood in combination with the other options.
다시 한번 분석하여 문제를 찾아보세요. 불행히도 이 명령은 나에게 효과적입니다. 내가 액세스할 수 있는 시스템이 사용 중이 sh -c "${ARGS}"
거나 유사하기 때문이라고 생각합니다. 그러나 귀하가 제공한 또 다른 오류는 힌트를 제공합니다.
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
exec
귀하의 시스템이 ... 에 대한 인수로 주어진 명령을 실행하는 데 사용하는 것 같습니다 ssh
. 이는 쉘이 귀하가 원하는 대로 처리할 수 없다는 것을 의미합니다. 따라서 if
경로 에 바이너리가 아니며 실패합니다. .;
if
마찬가지로 모든 인수가 sudo
한 번에 제공됩니다.
sudo
apt-get
update;
bash
-l
-c
"bash"
물론, sudo
의 (목록) 인수는 (로그인 클래스) -l
와 상호 배타적입니다 .-c