while, until, for 루프의 코드 블럭, 심지어는 if/then 테스트문 블럭도 표준입력의 재지향을 받아 들일 수 있습니다. 함수조차도 이런 형태의 재지향을 할 수 있습니다(예 23-7 참고). 이렇게 하려면, 해당 코드 블럭의 제일 끝에 < 연산자를 두면 됩니다.
예 16-2. 재지향된 while 루프
#!/bin/bash if [ -z "$1" ] then Filename=names.data # 파일이름이 지정되지 않을 경우의 기본값. else Filename=$1 fi # Filename=${1:-names.data} # 라고 해도 됩니다(매개변수 치환). count=0 echo while [ "$name" != Smith ] # $name 을 왜 쿼우트 했을까요? do read name # 표준입력이 아니라 $Filename 에서 읽음. echo $name let "count += 1" done <"$Filename" # 표준입력을 $Filename 파일로 재지향. # ^^^^^^^^^^^^ echo; echo "$count 개의 이름을 읽었습니다."; echo # 몇몇 오래된 쉘 스크립트 언어에서는 재지향된 루프가 서브쉘로 돕니다. # 그렇기 때문에, $count 가 루프 밖에서 초기화되어 0 을 리턴합니다. # Bash 와 ksh 은 가능한한 서브쉘을 안 띄우려고 하기 때문에 # 이 스크립트는 제대로 동작합니다. # Heiner Steven 이 이 점을 지적해 주었습니다. exit 0 |
예 16-3. 다른 형태의 재지향된 while 루프
#!/bin/bash # 이 스크립트는 앞서 소개해 드렸던 스크립트의 다른 형태입니다. # Heiner Steven 이 제공해 준 것으로, # 재지향 루프가 서브쉘로 돌 경우에 루프 안의 변수값이 # 루프 종료후 그 값을 잃어 버리는 것에 대한 해결책입니다. if [ -z "$1" ] then Filename=names.data # 파일이름이 지정되지 않았을 경우의 기본값. else Filename=$1 fi exec 3<&0 # 표준입력을 3번 파일 디스크립터로 저장. exec 0<"$Filename" # 표준입력을 재지향. count=0 echo while [ "$name" != Smith ] do read name # 재지향된 표준입력($Filename)에서 읽음. echo $name let "count += 1" done <"$Filename" # 루프는 $Filename 파일에서 입력을 받음. # ^^^^^^^^^^^^ exec 0<&3 # 원래 표준입력을 복구. exec 3<&- # 임시 파일 디스크립터 3번을 닫음. echo; echo "$count 개의 이름을 읽었습니다."; echo exit 0 |
예 16-4. 재지향된 until 루프
#!/bin/bash # 앞의 예제와 똑같으나 "until" 루트를 사용. if [ -z "$1" ] then Filename=names.data # 파일이름이 지정되지 않았을 경우의 기본값. else Filename=$1 fi # while [ "$name" != Smith ] until [ "$name" = Smith ] # != 를 = 로 바꿔주세요. do read name # 표준입력이 아니라 $Filename 에서 읽어 들입니다. echo $name done <"$Filename" # 표준입력을 $Filename 파일로 재지향. # ^^^^^^^^^^^^ # 앞 예제의 "while" 루프와 똑같은 결과가 나옵니다. exit 0 |
예 16-5. 재지향된 for 루프
#!/bin/bash if [ -z "$1" ] then Filename=names.data # 파일이름이 지정되지 않을 경우의 기본값. else Filename=$1 fi line_count=`wc $Filename | awk '{ print $1 }'` # 대상 파일의 줄 수. # "for" 루프에서 표준입력을 재지향 하는게 아주 부자연스러워 보이고 # 구현하기 까다롭겠지만, 여러분이 충분히 똑똑하다면 가능합니다. # # 좀 더 간단하게 하려면 line_count=$(wc < "$Filename") for name in `seq $line_count` # "seq"가 연속된 숫자를 출력한다는 거, 기억나시죠? # while [ "$name" != Smith ] -- "while" 루프보다 더 복잡합니다. -- do read name # 표준입력이 아닌 $Filename 에서 읽어 들입니다. echo $name if [ "$name" = Smith ] # 이런 작업을 추가적으로 덧붙여야 합니다. then break fi done <"$Filename" # 표준입력이 $Filename 에서 재지향 됨. # ^^^^^^^^^^^^ exit 0 |
바로 앞의 예제를 조금 변경하면 루프의 출력도 재지향 할 수 있습니다.
예 16-6. 재지향된 for 루프(표준입력, 표준출력 모두 재지향됨)
#!/bin/bash if [ -z "$1" ] then Filename=names.data # 파일이름이 지정되지 않을 경우의 기본값. else Filename=$1 fi Savefile=$Filename.new # 결과를 저장할 파일이름. FinalName=Jonah # "read" 시에 마지막 입력이 될 이름. line_count=`wc $Filename | awk '{ print $1 }'` # 대상 파일의 줄 수. for name in `seq $line_count` do read name echo "$name" if [ "$name" = "$FinalName" ] then break fi done < "$Filename" > "$Savefile" # 표준입력을 $Filename으로 재지향하고, # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 그 결과를 백업 파일로 저장. exit 0 |
예 16-7. 재지향된 if/then 테스트
#!/bin/bash if [ -z "$1" ] then Filename=names.data # 파일이름이 지정되지 않을 경우의 기본값. else Filename=$1 fi TRUE=1 if [ "$TRUE" ] # if true 와 if : 도 동작합니다. then read name echo $name fi <"$Filename" # ^^^^^^^^^^^^ # 파일의 첫번째 줄만 읽어 들임. # "if/then" 테스트문은 루프안에서 쓰이지 않는 한, 반복해서 비교할 방법이 없습니다. exit 0 |
코드 블럭의 표준출력을 재지향하는 것은 그 출력을 파일로 저장하는 효과를 가져옵니다. 예 4-2를 참고하세요.
참고: Here documents는 특별한 종류의 재지향된 코드 블럭입니다.