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
ssh
DeRobert 가 설명했듯이 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 입력은 다른 소스로 전환되어야 합니다.