1. Args의 스크립트

1. Args의 스크립트

머신 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

원격 호스트에서 스크립트를 실행하려는 경우그리고대화형 쉘을 얻으면 두 가지 옵션이 있습니다.

  1. 전체 스크립트를 의 명령줄 인수에 넣습니다 ssh.
  2. 스크립트를 원격 호스트에 푸시한 다음(예: 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한 번에 제공됩니다.

  1. sudo
  2. apt-get
  3. update;
  4. bash
  5. -l
  6. -c
  7. "bash"

물론, sudo의 (목록) 인수는 (로그인 클래스) -l와 상호 배타적입니다 .-c

관련 정보