14. I/O 재지향(Redirection)
셸은 항상 기본적으로 표준입력(stdin
, 키보드), 표준출력(stdout
, 스크린), 표준에러(stderr
, 스크린에 뿌려질 에러 메시지) 파일들을 열어 놓는다. 이 파일들을 포함해서 열려 있는 어떤 파일이라도 재지향될 수 있다. 재지향이란 간단히 말해서 파일, 명령어, 프로그램, 스크립트, 심지어 스크립트 속의 코드 블럭의 출력을 낚아 채서 다른 파일, 명령어, 프로그램, 스크립트의 입력으로 보내는 것이다.
열려 있는 파일 각각은 파일 디스크립터를 할당 받는다. 표준입력, 표준출력, 표준에러에 해당하는 파일 디스크립터는 각각 0
, 1
, 2
이다. 추가적으로 열리는 파일을 위해서 3
부터 9
까지의 파일 디스크립터가 남겨져 있다. 종종 이 추가적인 파일 디스크립터들 중의 하나를 표준입력, 표준출력, 표준에러로 할당해서 임시적인 중복된 링크로 쓰는 것이 유용할 때가 있다.
>
는 표준출력을 파일로 재지향한다. 파일이 없으면 새로 만들고, 있다면 덮어 쓴다.
# 디렉터리 트리 목록을 파일로 저장해 줌
ls -lR >dir-tree.list
# >는 "filename"의 길이가 0이 되도록 잘라줌
# :는 아무 출력도 안 하는 더미 플레이스홀더로 동작함
: >filename
>>
는 표준출력을 파일로 재지향한다. 파일이 없으면 새로 만들고 있다면, 파일 끝에 덧붙인다.
2>&1
는 표준에러(2
번 파일 디스크립터)를 표준출력(1
번 파일 디스크립터)으로 재지향한다. 에러 메시지는 표준출력의 자격으로 스크린에 보내진다. 이와 마찬가지로 i>&j
는 i
번 파일 디스크립터를 j
번 파일 디스크립터로 재지향한다. i
번 파일 디스크립터가 가리키는 파일의 모든 출력은 j
번 파일 디스크립터가 가리키는 파일로 보내진다. 참고로 >&j
는 기본적으로 표준출력(1
번 파일 디스크립터)를 j
번 파일 디스크립터로 재지향한다.
0<
또는 <
는 파일에서 입력을 받도록 해준다.
[j]<>filename
은 filename
을 읽기 및 쓰기용으로 열고, j
번 파일 디스크립터를 할당한다. filename
이 없다면 새로 만들고, filename
이 주어지지 않으면 기본적으로 표준입력인 0
번 파일 디스크립터가 할당된다.
# 이를 응용하면 파일의 특정한 위치에 쓰기를 할 수 있음
# "File"에 문자열 작성
echo 1234567890 >File
# "File"을 열고 3번 파일 디스크립터 할당
exec 3<>File
# 3번 파일 디스크립터에서 문자 4개를 읽음
read -n 4 <&3
# 문자 4개를 읽은 자리에 .(점)을 씀
echo -n . >&3
# 3번 파일 디스크립터를 닫음
exec 3>&-
cat File
1234.67890
|
는 프로세스와 명령어를 엮어 주는 일반적인 목적의 툴이다. >
와 비슷하지만, 명령어, 스크립트, 파일, 프로그램들을 함께 묶는 데 유용하게 사용된다.
# 모든 .txt 파일의 출력을 정렬한 다음, 중복되는 줄을 제거하고
# 그 결과를 "result-file"에 저장
cat *.txt | sort | uniq >result-file
다음과 같이 여러 개의 출력 스트림이 한 파일로 재지향될 수도 있다.
# "ls"의 잘못된 옵션인 "yz"의 결과를 "command.log"로 저장
# 표준에러(2번 파일 디스크립터)가 표준출력(1번 파일 디스크립터)으로 재지향
# 현재 command.log로 출력이 되므로 에러 메시지는 "command.log"에 저장됨
ls -yz >>command.log 2>&1
n<&-
는 n
번 입력 파일 디스크립터를 닫아 주고, n>&-
는 n
번 출력 파일 디스크립터를 닫아 준다.
0<&-
또는 <&-
는 표준입력(0
번 파일 디스크립터)를 닫아 주고, 1>&-
또는 >&-
는 표준출력(1
번 파일 디스크립터)를 닫아 준다.
자식 프로세스는 열려 있는 파일 디스크립터를 상속 받는데, 이것 때문에 파이프가 동작한다. 만약 파일 디스크립터가 상속되길 바라지 않는다면 그 파일 디스크립터를 닫으면 된다.
# 파이프로 퓨준에러만 재지향하기
# 표준출력의 현재 "값"을 저장
# 3번 파일 디스크립터를 1번 파일 디스크립터로 재지향
exec 3>&1
# "ls"와 "grep"을 위해 3번 파일 디스크립터를 닫음
ls -l 2>&1 >&3 3>&- | grep bad 3>&-
# 스크립트 나머지 부분을 위해 닫음
exec 3>&-