해결책

해결책

servers.txt서버 목록이 포함된 파일이 있습니다 .

server1.mydomain.com
server2.mydomain.com
server3.mydomain.com

파일을 한 줄씩 읽고 while각 줄을 에코하면 모든 것이 예상대로 작동합니다. 모든 줄이 인쇄됩니다.

$ while read HOST ; do echo $HOST ; done < servers.txt
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com

그러나 모든 서버에 SSH를 통해 명령을 실행하려고 하면 루프가 while갑자기 작동을 멈춥니다.

$ while read HOST ; do ssh $HOST "uname -a" ; done < servers.txt
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux

이는 모든 서버가 아닌 목록의 첫 번째 서버에만 연결됩니다. 나는 여기서 무슨 일이 일어나고 있는지 이해하지 못합니다. 누군가 이것을 설명할 수 있나요?

for루프를 사용하면 잘 작동하기 때문에 이것은 더욱 이상합니다 .

$ for HOST in $(cat servers.txt ) ; do ssh $HOST "uname -a" ; done
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server2 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server3 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux

ssh다른 명령은 제대로 작동하므로 해당 명령에만 적용되어야 합니다 ping. 예를 들면 다음과 같습니다.

$ while read HOST ; do ping -c 1 $HOST ; done < servers.txt

답변1

ssh표준 입력의 나머지 부분을 읽는 중입니다.

while read HOST ; do … ; done < servers.txt

read표준 입력에서 읽습니다. <파일에서 표준 입력을 리디렉션합니다.

불행하게도 실행하려는 명령은 표준 입력도 읽으므로 결국 파일의 나머지 부분을 먹어치워지게 됩니다. 다음을 사용하여 명확하게 볼 수 있습니다.

$ while read HOST ; do echo start $HOST end; cat; done < servers.txt 
start server1.mydomain.com end
server2.mydomain.com
server3.mydomain.com

나머지 두 줄이 어떻게 cat삭제되고 에코되는지 확인하세요. (예상대로 완료되면 각 줄에는 호스트 주위에 "시작"과 "끝"이 표시됩니다.)

for작동합니까?

귀하의 for회선은 표준 입력으로 리디렉션되지 않습니다. (실제로 servers.txt첫 번째 반복 전에 파일의 전체 내용을 메모리로 읽어옵니다.) 따라서 ssh터미널에서 표준 입력을 계속 읽으십시오(또는 스크립트 호출 방법에 따라 아무것도 읽지 않을 수도 있음).

해결책

적어도 bash에서는 read다른 파일 설명자를 사용할 수 있습니다.

while read -u10 HOST ; do ssh $HOST "uname -a" ; done 10< servers.txt
#          ^^^^                                       ^^

작동해야합니다. 10내가 선택한 파일 번호만 있으면 됩니다. 0, 1, 2는 정의된 의미를 가지며 일반적으로 파일 열기는 사용 가능한 첫 번째 숫자로 시작됩니다(따라서 3이 다음에 사용됩니다). 따라서 10은 방해가 되지 않을 만큼 높지만 일부 포탄의 한계보다 낮을 만큼 낮습니다. 게다가 그것은 좋은 둥근 숫자입니다 ...

대체 솔루션 1: -n

~처럼맥니스에서 지적하다그/그녀의 대답, OpenSSH 클라이언트에는 -n표준 입력을 읽지 못하게 하는 옵션이 있습니다. 이것은 특정 경우에 잘 작동 ssh하지만 물론 다른 명령에는 이것이 부족할 수 있습니다. 다른 솔루션은 어떤 명령이 표준 입력을 사용하는지에 관계없이 작동합니다.

대체 솔루션 2: 두 번째 리디렉션

분명히 당신은 다음과 같이 두 번째 리디렉션을 수행할 수 있습니다(예를 들어, 시도했고 적어도 내 Bash 버전에서는 작동했습니다...).

while read HOST ; do ssh $HOST "uname -a" < /dev/null; done < servers.txt

어떤 명령에도 사용할 수 있지만 실제로 터미널 입력을 명령에 포함시키려는 경우에는 어렵습니다.

답변2

sshDeRobert 가 설명했듯이 stdin.

이 동작을 변경하려면 -n no ssh를 추가하여 표준 입력을 읽지 못하게 할 수 있습니다.

ssh -n $HOST "uname -a"

답변3

실제로 사용하는 것이 더 나을 것입니다.퍼프 퍼프~에서병렬 SSH프로젝트.

pssh -h $hostfile -t $timeout -i $commands

-i상호작용을 의미합니다. pssh에는 병렬 scp 및 병렬 rsync도 함께 제공됩니다. 장점은 비동기식으로 실행되며 필요한 만큼 스레드를 실행할 수 있다는 것입니다. 기본값(비i/interactive)은 $outputdir/$hostname을 통해 수행되는 stdout/stderr에 대한 별도의 디렉토리에 출력하는 것입니다.

답변4

ssh 명령은 while 문에서 제공하는 표준 입력에서 모든 스트림을 가져오기 때문에

파이프를 사용하여 SSH의 표준 입력을 다른 소스로 전환할 수 있습니다.

echo "" | ssh ...

예:

while read HOST ; do echo "" | ssh $HOST "uname -a" ; done < servers.txt

while 루프의 모든 ssh 명령에 대한 stdin 입력은 다른 소스로 전환되어야 합니다.

관련 정보