가짜 A 터미널

가짜 A 터미널

매우 유사하다.bashrc를 얻은 후 ssh를 사용하여 대화형 셸에서 명령을 실행합니다., 그러나 거기에 대한 답변은 나에게 도움이 되지 않았습니다.

완전한 대화형 셸에서 SSH를 통해 원격 명령을 실행하고 싶습니다. 즉,
로그인 셸에서 일부 매개변수를 사용하여 원격 명령을 실행합니다.

기본적으로 작동하려면 다음 두 가지가 필요합니다.

ssh user@remote_computer -t bash -l -c '/bin/echo PATH is $PATH'
ssh user@remote_computer -t 'bash -l -c "java -version"'

java: command not found하지만 현재 사례 1과 사례 2에서 빈 줄이 표시됩니다.

$ ssh user@remote_computer -t bash -l -c '/bin/echo PATH is $PATH'

Connection to remote_computer closed.

$ ssh user@remote_computer -t bash -l -c 'true; /bin/echo PATH is $PATH'
PATH is /usr/local/bin:/usr/bin:/bin:/usr/games
Connection to remote_computer closed.

ssh user@remote_computer -t bash -l -c 'true; java -version'
bash: line 1: java: command not found
Connection to remote_computer closed.

고쳐 쓰다:

적어도 두 사람은 이것이 인용 문제라고 생각하지만, 이것이 인용 문제인 이유와 위에서 원하는 것을 어떻게 얻을 수 있는지 설명해 주시겠습니까? 예를 들어, 제가 시도한 것은 다음과 같습니다.

ssh user@remote_computer -t 'bash -l -c "java -version"'
bash: line 1: java: command not found
Connection to remote_computer closed.

나는 그것을 다른 방식으로 참조하는 방법을 이미 모릅니다. 도와주세요!

나중에 동일한 명령을 실행하면 다음과 같은 결과 ssh user@remote_computer가 나타납니다.

$ bash -l -c "java -version"
openjdk version "11.0.15" 2022-04-19 LTS
OpenJDK Runtime Environment Zulu11.56+19-CA (build 11.0.15+10-LTS)
OpenJDK 64-Bit Server VM Zulu11.56+19-CA (build 11.0.15+10-LTS, mixed mode)

따라서 이것은 분명히 나에게 인용 문제가 아닙니다.

답변1

-cSSH를 통한 쉘 명령은 여기에서 문제가 있습니다. 몇 가지 까다로운 인용 문제가 있으며 누가 무엇을 언제 실행하고 있는지 잘 모르겠습니다. 테스트 목적으로 여기에서 customjava읽은 내용 만 알려져 있습니다. ~/.bashrcZSH는 내 기본 쉘입니다.

$ ssh -t localhost bash -c 'source ~/.bashrc;customjava -version'
/home/jhqdoe/.bashrc: line 0: source: filename argument required
source: usage: source filename [arguments]
zsh:1: command not found: customjava
Connection to 127.0.0.1 closed.
$ ssh -t localhost bash -c ':;source ~/.bashrc;customjava -version'
java version 99999
Connection to 127.0.0.1 closed.

위의 두 명령 사이의 차이점을 이해하기 위해 strace몇 가지 작업을 수행하고 소스 코드를 자세히 살펴볼 수 있다고 생각합니다 ( 빈 명령이고 실제보다 입력이 적습니다 ). 하지만 이미 너무 취약하고 디버깅하기 어려운 경우 , 다른 해결책을 찾아보겠습니다. 내가 선호하는 것은 일반적으로 전체 명령을 인용하는 것입니다.ssh -v -v -v:true

$ ssh localhost 'bash -ic "customjava -version"'
java version 99999

그러나 더 복잡한 인용 요구 사항과 변수 대체가 명령에 포함되는 경우 이는 너무 복잡해질 수 있습니다. (복잡한 쉘 인용문은 새벽 2시에 디버깅하고 싶은 내용이 아니므로 기본적으로 피하는 경향이 있습니다.)

파이프 대신

대안은 명령을 원하는 셸로 파이프하는 것입니다. 이렇게 하면 명령 실행의 복잡성이 최소화되어 선택적 셸 호출이 가능해집니다.

$ printf 'customjava -version'"\n" | ssh localhost 'bash -i'
bash$ customjava -version
java version 99999
bash$ exit
$ printf 'customjava -version'"\n" | ssh localhost 'bash -l'
java version 99999

여기서 단점은 표준 입력이 터미널이 아니기 때문에 상대방의 명령에 터미널이 필요한 경우 작동하지 않는다는 것입니다. 이에 대한 경고가 있을 수 있습니다.

$ printf 'customjava -version'"\n" | ssh localhost
Pseudo-terminal will not be allocated because stdin is not a terminal.
zsh: command not found: customjava
$ printf 'customjava -version'"\n" | ssh -t localhost
Pseudo-terminal will not be allocated because stdin is not a terminal.
zsh: command not found: customjava

가짜 A 터미널

터미널이 필요한 경우 아마도 로 전환할 것입니다 expect. 이렇게 하면 명령이 실행될 가짜 터미널이 생성됩니다.

#!/usr/bin/env expect

spawn -noecho ssh localhost

# assume a prompt containing at least "% " (ZSH)
expect "% "

# replace ZSH with another shell
send -- "exec bash\n"
# assume a prompt of at least "$ "
expect "$ "
send -- "customjava -version\n"
expect "$ "
set version_info $expect_out(buffer)
send -- "exit\n"

puts "got >>>$version_info<<<"

그러나 특히 오류 검사 및 쉘 프롬프트 감지와 관련된 다른 문제가 있습니다(예: 누군가가 이를 조작하고 있을 수 있으므로 가장 먼저 해야 할 일은 프롬프트를 알려진 값과 expect일치하도록 설정하는 것일 수 있습니다). 누군가가 다양한 방법 중 하나로 대화형 셸 구성을 손상시키는 경우에도 충돌이 발생할 수 있습니다. 어쩌면 달리고 /bin/sh싶지 않을까요 bash? 그러나 사용자 sh정의 Java를 구성해야 할 수도 있습니다 . 이로 인해...

셸에서 구성 제거

이 문제를 해결하는 또 다른 방법은 환경을 올바르게 구성하는 SSH 서버에 특수 명령(예: exec 래퍼)을 작성한 다음 해당 java명령이나 다른 명령을 실행하는 것입니다. 그런 다음 setup-our-env bash(사람이 사용할 수 있는 대화형 셸) 또는 setup-our-env java -version(대화형 셸의 복잡함 없이 SSH를 통해 실행되는 간단한 명령)을 실행할 수 있습니다 . Exec 래퍼는 다음과 같이 간단할 수 있습니다.

#!/bin/sh
PATH=/custom/java/bin:$PATH
exec "$@"

즉, 사용자 정의 Java 버전의 환경 설정은 대화형 셸 구성과 완전히 혼합되지 않으므로 원하는 명령에 적용할 수 있습니다.

관련 정보