원격 컴퓨터에서 아래 스크립트를 실행하려고 하는데 여기서 두 가지 문제에 직면했습니다.
- 여기 문서에 정의된 while 루프는 무한히 실행됩니다.
- Enter 키 읽기가 원격 호스트에서 작동하지 않습니다
스크립트는 sshpass 명령 없이 localhost에서 제대로 작동합니다.
누군가 이 문제를 조사하고 도와줄 수 있나요?
1 #!/bin/bash
2 #read -p "Enter the user name to connect to server: " user
3 #read -s -p "Enter the password : " passd
4 #sshpass -p $passd ssh -qt -o StrictHostKeyChecking=no -o ConnectTimeout=4 $user@$1 << 'MYSCR'
5 ##############################################################################################################################################
6 while :
7 do
8 clear
9 echo "Server Name - $(hostname)"
10 echo "1. Check Server Information"
11 echo "2. Check Network Information"
12 echo "q. to Exit"
13 read -p "Enter your choice [ 1 - 3 ]" choice
14 case $choice in
15 1)
16 echo "Server Date : `date`"
17 echo "Server Uptime :`uptime`"
18 read -p "Press [Enter] key to continue..."
19 readEnterKey
20 ;;
21 2)
22 echo "File system information"
23 df -hP | column -t
24 read -p "Press [Enter] key to continue..."
25 readEnterKey
26 ;;
27 q)
28 echo "Bye!"
29 exit 0
30 ;;
31 *)
32 echo "Error: Invalid option..."
33 read -p "Press [Enter] key to continue..."
34 readEnterKey
35 ;;
36 esac
37 done
38 #MYSCR
답변1
몇 가지 문제:
한 줄을 읽으면 입니다
IFS= read -r line
.read -s -p "Enter the password : " passd
특히 비밀번호에 백슬래시가 포함되어 있거나 문자로 시작하거나 끝나는 사용자의 경우에는 작동하지 않습니다$IFS
. 그래서 그래야 한다IFS= read -rsp 'Enter the password: ' passd || exit
Bash에서는 목록 컨텍스트의 매개변수 확장을 인용해야 합니다.
"$user@$1"
,$user@$1
예가 아닙니다.-o StrictHostKeyChecking=no
좀 그런 것 같아나를 깨뜨려주세요. 네트워크를 완전히 신뢰할 수 없는 경우 클라이언트에 대해 서버를 인증하는 것은 서버에 대해 클라이언트를 인증하는 것만큼 중요합니다. 지시어는 다음과 같습니다."신원 증명을 요구하지 않고 사용자가 자신이 누구인지 신뢰합니다."서버 측에서 완료되면.암호 및 기타 비밀 정보는 시스템 내의 공개 정보이므로 명령 매개변수에 전달되어서는 안 됩니다. 매뉴얼
sshpass
페이지에는 이에 대한 큰 경고가 있습니다.SSHPASS="$passd" sshpass -e ssh...
비밀번호 인증보다 더 나은 형태의 인증을 사용 하거나 계속 사용하는 것이 좋습니다.unset
변수가 비밀 데이터를 저장하도록 하기 전에 해당 변수 가 환경으로 내보내지지 않도록 처리하는 것이 좋습니다 (명령으로 누출되어 그 자체로 더 누출될 수 있습니다. 여기서는 그렇지 않을 수도 있습니다. 조건). Bash에서는unset -v passd
.를 사용하면
sshpass ... ssh ... << 'HEREDOC'
문서가 원격 명령에sshpass
전달되는 표준 입력이 됩니다.ssh
여기에서는 실행하려는 명령을 지정하지 않으므로 그것이 무엇이든 원격 사용자의 로그인 셸이 됩니다.stdin은 터미널 장치가 아니기 때문에 원격 측에 의사 터미널을 만들지 말라고
ssh
요청하며 , 그렇게 하더라도 쉘은 비대화형으로 시작됩니다. 그렇지 않으면 프롬프트를 에코하고 대화형 쉘을 실행하기 시작합니다. 스크립트가 실행될 때 하고 싶은 모든 것.sshd
-t
따라서 여기서 쉘은 표준 입력에서 실행될 코드를 읽습니다.
그러나 해당 코드는 표준 입력에서도 읽습니다. 는
read -p "Enter your choice [ 1 - 3 ]" choice
이 정리에서 읽혀질 것입니다. 고맙게도read
쉘이 전체 루프에 대한 코드를 읽을 때까지 실행되지 않으므로while
여기 문서에서 뒤에 나오는 내용만 읽거나, 뒤에 아무것도 없으면 무엇이든 읽고 eof에서 실패를 반환합니다.
bash
여기서는 사용자의 로그인 셸(bash를 로그인 셸로 사용하는 사람은 누구입니까? :-b)이 아닌 원격 호스트에서 셸을 실행해야 합니다(bash 특정 구문을 사용하므로). 비대화형으로 실행하고 코드를 전달합니다. stdin을 거치는 것 외에 다른 방법으로. AcceptEnv LC_*
SSH 서버 구성에 몇 가지 일반적인 구성이 있는 경우 다음을 수행할 수 있습니다.
code=$(
cat <<'EOF'
the code there
EOF
)
그런 다음:
SSHPASS="$passd" LC_CODE="$code" sshpass -e ssh -o SendEnv=LC_CODE -qt "$user@$1" '
exec bash -c -- "$LC_CODE"'
이는 원격 호스트의 로그인 쉘이 변수를 인용하는 $user
구문을 이해하고 $var
인용에 큰따옴표를 사용할 수 있다고 가정합니다(Bourne과 같은 쉘에서는 분할+글로브를 피하기 위해 필요합니다). 로그인 쉘이 or 또는 의 파생물이면 충분 합니다 rc
( 인용 부호 는 유사한 쉘에만 해롭습니다 ) .zsh
fish
exec bash -c -- $LC_CODE
rc
csh
tcsh
exec bash -c -- $LC_CODE:q
그것을 쓰세요:
SSHPASS="$passd" LC_CODE="$code" sshpass -e ssh -o SendEnv=LC_CODE -qt "$user@$1" '
exec bash -c '\''eval -- "$LC_CODE"'\'
이는 사용자의 로그인 쉘이 위 중 하나일 경우 작동합니다. 왜냐하면 bash -c 'eval -- "$LC_CODE"'
적어도 모든 Bourne 유사, rc 유사, csh 유사 및 Fish 쉘이 동일한 코드를 이해하기 때문입니다. ps -Awww
이 코드가 원격 호스트의 출력에 노출되지 않는다는 장점도 있습니다 .
다음에서 자세히 알아볼 수 있습니다.원격 사용자의 로그인 셸을 모르고 SSH를 통해 임의의 간단한 명령을 어떻게 실행할 수 있습니까?
SSHPASS="$passd" sshpass -e ssh -qt "$user@$1" " $code"
@aviro의 답변(또는로 시작하는 경우에 필요한 추가 공간 추가 $code
)은 사용자의 로그인 셸이 . 또한 로컬 및 원격 시스템 모두에 대한 출력에 코드가 노출된다는 점에 유의하세요.$code
-
+
bash
ps -Awww
¹ 이 경우에는 그렇습니다 sshd
. bash -c thatcode
그리고 적어도 현재 버전의 openssh에서는 이를 수행하지 않습니다 bash -c -- thatcode
(아마도 모든 쉘이 이를 지원하거나 요구하지 않기 때문 --
이거나 문제 때문에(실제로는 덜 발생할 수 있음) 무시됨;C 언어에도 같은 문제가 있습니다system()
수십년 동안 방치됨)
답변2
이 문서를 사용하면 텍스트가 표준 입력(표준 입력) 프로세스, 이 경우 -표준 입력귀하의 ssh
프로세스. 이 문서를 다음으로 리디렉션했기 때문에표준 입력당신의 ssh
키보드를 읽을 수 없습니다.
안으로보다는표준 입력ssh를 사용하여 변수에 할당한 다음 해당 변수를 ssh
명령으로 사용하여 원격 호스트에서 실행합니다.
# Read the here-document into the $COMMAND variable
read -r -d '' COMMAND << 'MYSCR'
while :
do
clear
...
MYSCR
# Run ssh with $COMMAND
sshpass -p $passd ssh -qt -o StrictHostKeyChecking=no -o ConnectTimeout=4 $user@$1 "$COMMAND"