읽기 행 루프가 첫 번째 행 이후에 중지되는 동안 쉘 스크립트


107

다음 셸 스크립트가 있습니다. 목적은 대상 파일의 각 행 (그 경로가 스크립트에 대한 입력 매개 변수)을 통해 반복하고 각 행에 대해 작업하는 것입니다. 이제 대상 파일의 첫 번째 줄에서만 작동하며 해당 줄이 처리 된 후 중지됩니다. 내 스크립트에 문제가 있습니까?

#!/bin/bash
# SCRIPT: do.sh
# PURPOSE: loop thru the targets 

FILENAME=$1
count=0

echo "proceed with $FILENAME"

while read LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh $LINE
done < $FILENAME

echo "\ntotal $count targets"

에서는 do_work.sh몇 가지 ssh명령을 실행 합니다.


1
스크립트는 잘하지만 do_work.sh에 뭔가 잘못이있을 수 있습니다
sleepsort

2
예, 모든 입력을 먹거나 source단순히 종료 또는 으로 호출 할 수 있습니다 exec. 그러나이 코드는 정품 보이지 않는, 그 반향을 알 것 영업 이익은 필요 -e... 제대로 표시 라인 피드
마이클 Krelin - 해커

3
혹시 do_work.sh달리 ssh나요?
개정 향풀

1
예, do_work.sh는 몇 가지 ssh 명령을 실행합니다. 그것에 대해 특별한 것이 있습니까?
bcbishop

1
do_work.sh소스 를 표시하고 디버그하기 위해 실행 do.sh하는 set -x것이 더 좋습니다 .
koola

답변:


178

문제는 명령 을 do_work.sh실행 ssh하고 기본적으로 ssh입력 파일 인 stdin에서 읽는다는 것입니다. 결과적으로 ssh파일의 나머지를 소비하고 while 루프가 종료 되기 때문에 처리 된 첫 번째 줄만 볼 수 있습니다.

이를 방지하려면 -n옵션을 ssh명령에 전달하여 /dev/nullstdin 대신 읽도록하십시오 .


1
매우 유용하여이 zsh oneliner를 실행하는 데 도움이되었습니다. cat hosts | 읽는 동안 호스트; do ssh $ host do_something; 완료
rat

3
@rat 당신은 여전히 쓸모없는cat 것을 피하고 싶습니다 . 당신은 특히 설치류가 이것을 경계 할 것이라고 생각할 것입니다.
tripleee

while read host ; do $host do_something ; done < /etc/hosts그것을 피할 것입니다. 그것은 상당한 생명의 은인입니다, 감사합니다!

httpie기본적으로 STDIN을 읽는 또 다른 명령이며 bash 또는 fish 루프 내에서 호출 될 때 동일한 동작이 발생합니다. 위와 같이 http --ignore-stdin표준 입력을 사용 하거나 설정합니다 /dev/null.
Raman

12

보다 일반적으로 다음과 관련된 해결 방법은 다음과 같습니다. sshwhile루프의 입력을 소비 할 수있는 명령에 대한 표준 입력을 리디렉션하는 것 입니다.

while read -r LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"

를 추가하는 </dev/null것이 여기서 중요한 점입니다 (수정 된 인용도 다소 중요합니다. 쉘 변수 주위에 인용 부호를 묶을 때 ). read -r없이 얻을 레거시 약간 이상한 동작이 특별히 필요하지 않는 한 사용하고 싶을 것 -r입니다.

다소 구체적인 또 다른 해결 방법 ssh 모든 ssh명령에 표준 입력이 묶여 있는지 확인 하는 것입니다.

ssh otherhost some commands here

대신 여기 문서에서 명령을 읽을 수 있습니다.이 문서는 편리하게 (이 특정 시나리오의 경우) ssh명령 에 대한 표준 입력 을 연결합니다.

ssh otherhost <<'____HERE'
    some commands here
____HERE

5

ssh -n 옵션은 출력을 다른 프로그램으로 파이핑하는 동안 HEREdoc을 사용할 때 ssh의 종료 상태를 확인하지 못하도록합니다. 따라서 stdin으로 / dev / null을 사용하는 것이 좋습니다.

#!/bin/bash
while read ONELINE ; do
   ssh ubuntu@host_xyz </dev/null <<EOF 2>&1 | filter_pgm 
   echo "Hi, $ONELINE. You come here often?"
   process_response_pgm 
EOF
   if [ ${PIPESTATUS[0]} -ne 0 ] ; then
      echo "aborting loop"
      exit ${PIPESTATUS[0]}
   fi
done << input_list.txt

이건 말이 안 돼. 이 리디렉션을 <<EOF재정의합니다 </dev/null. <<뒤 의 리디렉션 done이 잘못되었습니다.
tripleee

1

내가했기 때문에 이것은 나에게 무슨 일이 일어나고 set -egrep루프에서이 (이 아닌 에러 코드를 제공하는) 어떠한 출력을 반환했다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.