Skip to content

16. 코드 블럭 재지향


while, until, for 루프의 코드 블럭, 심지어 if/then 테스트문 블럭도 표준입력의 재지향을 받아 들일 수 있다. 함수조차도 이런 형태의 재지향을 할 수 있다. 이렇게 하려면, 해당 코드 블럭의 제일 끝에 < 연산자를 두면 된다.


예제) 재지향된 while 루프
#!/bin/bash

# "names.data" 파일의 내용
# Hello
# Bye
# Smith

if [ -z "$1" ]; then
    # 파일이름이 지정되지 않을 경우의 기본값
    Filename=names.data
else
    Filename="$1"
fi

count=0

while [ "$name" != "Smith" ]; do
    # 표준입력이 아니라 "$Filename"에서 읽음
    read name
    echo "$name"
    count=$(($count + 1))
    # 표준입력을 "$Filename" 파일로 재지향
done <"$Filename"
# Hello
# Bye
# Smith

echo "$count 개의 이름을 읽었습니다."
# 3 개의 이름을 읽었습니다.

exit 0


몇몇 오래된 셸 스크립트 언어에서는 재지향된 루프가 서브셸로 돌게 된다. 그렇기 때문에, $count가 루프 밖에서 초기화되어 0을 리턴한다.


#!/bin/bash

# "names.data" 파일의 내용
# Hello
# Bye
# Smith

if [ -z "$1" ]; then
    # 파일이름이 지정되지 않을 경우의 기본값
    Filename=names.data
else
    Filename="$1"
fi

# 표준입력을 3번 파일 디스크립터로 임시 저장
exec 3<&0
# 표준입력을 재지향
exec 0<"$Filename"

count=0

while [ "$name" != "Smith" ]; do
    # 표준입력이 아니라 "$Filename"에서 읽음
    read name
    echo "$name"
    count=$(($count + 1))
    # 표준입력을 "$Filename" 파일로 재지향
done <"$Filename"
# Hello
# Bye
# Smith

# 원래 표준입력 복구
exec 0<&3
# 임시 파일 디스크립터를 닫음
exec 3<&-

echo "$count 개의 이름을 읽었습니다."
# 3 개의 이름을 읽었습니다.

exit 0
#!/bin/bash

# "names.data" 파일의 내용
# Hello
# Bye
# Smith

if [ -z "$1" ]; then
    # 파일이름이 지정되지 않을 경우의 기본값
    Filename=names.data
else
    Filename="$1"
fi

# 표준입력을 3번 파일 디스크립터로 임시 저장
exec 3<&0
# 표준입력을 재지향
exec 0<"$Filename"

count=0

# while [ "$name" != "Smith" ]; do
until [ "$name" = "Smith" ]; do
    # 표준입력이 아니라 "$Filename"에서 읽음
    read name
    echo "$name"
    count=$(($count + 1))
    # 표준입력을 "$Filename" 파일로 재지향
done <"$Filename"
# Hello
# Bye
# Smith

# 원래 표준입력 복구
exec 0<&3
# 임시 파일 디스크립터를 닫음
exec 3<&-

echo "$count 개의 이름을 읽었습니다."
# 3 개의 이름을 읽었습니다.

exit 0
#!/bin/bash

# "names.data" 파일의 내용
# Hello
# Bye
# Smith

if [ -z "$1" ]; then
    # 파일이름이 지정되지 않을 경우의 기본값
    Filename=names.data
else
    Filename="$1"
fi

# 대상 파일의 줄 수
line_count=$(wc "$Filename" | awk '{ print $1 }')
# line_count=$(wc < "Filename")

for name in $(seq "$line_count"); do
    read name
    echo "$name"

    if [ "$name" = "Smith" ]; then
        break
    fi
done <"$Filename"
# Hello
# Bye
# Smith

echo "$line_count 개의 이름을 읽었습니다."
# 3 개의 이름을 읽었습니다.

exit 0
#!/bin/bash

# "names.data" 파일의 내용
# Hello
# Bye
# Smith

if [ -z "$1" ]; then
    # 파일이름이 지정되지 않을 경우의 기본값
    Filename=names.data
else
    Filename="$1"
fi

# 결과를 저장할 파일이름
Savefile="${Filename}.new"
# "read" 시에 마지막 입력이 될 이름
FinalName="Jonah"

# 대상 파일의 줄 수
line_count=$(wc "$Filename" | awk '{ print $1 }')
# line_count=$(wc < "Filename")

for name in $(seq "$line_count"); do
    read name
    echo "$name"

    if [ "$name" = "Smith" ]; then
        echo "$FinalName"
        break
    fi
    # 표준입력을 "$Filename"으로 재지향하고
    # 그 결과를 백업 파일로 저장
done <"$Filename" >"$Savefile"
# "names.data.new" 파일의 내용
# Hello
# Bye
# Smith
# Jonah

exit 0
#!/bin/bash

# "names.data" 파일의 내용
# Hello
# Bye
# Smith

if [ -z "$1" ]; then
    # 파일이름이 지정되지 않을 경우의 기본값
    Filename=names.data
else
    Filename="$1"
fi

TRUE=1

# if True 또는 if :도 동작함
if [ "$TRUE" ]; then
    read name
    echo "$name"
fi <"$Filename"

# 파일의 첫 번째 줄만 읽어 들임
# "if/then" 테스트문은 루프 안에서 쓰이지 않는 한
# 반복해서 비교할 방법이 없음

exit 0

References