[쉘 스크립트] 쉘 스크립트 기초 - 데이터 보여주기 (5)
카테고리: Linux
태그: Linux
표준 출력, 표준 에러 리다이렉트
STDERR 및 STDOUT 출력을 같은 파일로 리다이렉트 할 수 있다. bash 쉘은 이러한 목적을 위한 특수한 기호인 &>를 제공한다.
&> 기호를 사용하면 명령이 만들어낸 모든 출력은 같은 장소에 전달된다. 다음은 해당 기호를 사용하여 표준 출력과 표준 에러를 같은 파일에 저장하는 예시이다.
$ ll test*
-rw-rw-r-- 1 vagrant vagrant 0 2월 13 19:54 test1
-rw-rw-r-- 1 vagrant vagrant 0 2월 13 19:54 test2
$ ll test1 test2 test3 test4 &> badtest
$ cat badtest
ls: cannot access 'test3': No such file or directory
ls: cannot access 'test4': No such file or directory
-rw-rw-r-- 1 vagrant vagrant 0 2월 13 19:54 test1
-rw-rw-r-- 1 vagrant vagrant 0 2월 13 19:54 test2
Note:
bash 쉘은 자동으로 표준 출력보다 오류 메시지에 높은 우선순위를 부여한다. 이 기능으로 오류 메시지는 보통 출력 파일에 흩어져 있기 보다 한데 모여있다.
일시 리다이렉트
스크립트에서 일부러 오류 메시지를 만들어내려는 경우, 표준 에러 디스크립터에 개별 출력을 리다이렉트할 수 있다. 파일 디스크립터로 리다이렉트할 때에는 &와 파일 디스크립터 번호를 앞에 두면된다.
다만, 기본적으로 리눅스는 표준 에러 출력을 표준 출력과 같은 곳으로 보낸다는 점을 기억해야한다. 표준 에러 출력을 변경하고 싶은 경우 2> 기호를 사용하여 리다이렉트할 곳을 정해줘야한다.
$ echo "This is an error message" >&2
This is an error message
$ echo "This is an error message" 2>message >&2
$ cat message
This is an error message
지속 리다이렉트
출력 리다이렉트
exec 명령을 사용하여 스크립트가 실행도디는 동안 특정한 파일 디스크립터를 리다이렉트 하도록 쉘에게 지시할 수 있다.
exec 명령은 새로운 쉘을 시작하고 STDOUT 파일 디스크립터를 파일로 리다이렉트한다. 스크립트에서 STDOUT로 가는 모든 출력은 파일로 리다이렉트된다.
$ cat exec.sh
#!/bin/bash
exec 1>testout
echo "This is a test of redirecting all output"
echo "from a script to another file"
echo "without having to redirect every individual line"
$ ./exec.sh
$ cat testout
This is a test of redirecting all output
from a script to another file
without having to redirect every individual line
입력 리다이렉트
STDOUT 및 STDERR을 리다이렉트할 때 썻던 기술을 STDIN에서도 사용할 수 있다. exec 명령은 STDIN을 리눅스 시스템의 파일로 리다이렉트할 수 있다.
$ cat testline
This is the first line
This is the second line
This is the third line
$ cat exec-stdin.sh
#!/bin/bash
exec 0< testline
count=1
while read line
do
echo "Line #${count}: $line"
count=$[ $count + 1 ]
done
$ ./exec-stdin.sh
Line #1: This is the first line
Line #2: This is the second line
Line #3: This is the third lin
파일 디스크립터 닫기
사용자 정의 STDOUT 또는 STDIN 디스크립터를 작성하는 경우 스크립트가 종료될 때 쉘은 자동으로 이들 디스크립터를 닫는다. 하지만 스크립트가 끝나기 전에 파일 디스크립터를 수동으로 닫아야 할 때가 있다.
파일 디스크립터를 닫으려면 이를 특수 기호인 &-로 리다이렉트한다. 다음은 닫힌 파일 디스크립터를 사용하려고 할 때 일어나는 일의 예시이다.
$ cat fd-close.sh
#!/bin/bash
exec 3> testout
echo "This is a test line of data" >&3
exec 3>&-
echo "This won't work" >&3
$ ./fd-close.sh
./fd-close.sh: line 6: 3: Bad file descriptor
열린 파일 디스크립터 나열
lsof 명령은 전체 리눅스 시스템에 열려 있는 모든 파일 디스크립터 목록을 보여준다. 이 명령은 어마어마한 양의 출력을 쏟아낸다. 이 명령은 리눅스 시스템에 열려 있는 모든 파일에 대한 정보를 표시한다.
lsof의 출력을 걸러내는 데 사용할 수 있는 가장 널리 사용되는 매개변수 및 옵션이 있다. 다음은 그 사용 예시이다.
-p: 프로세스 ID를 지정할 수 있다.-d: 표시할 파일 디스크립터 번호를 지정할 수 있다.-a: 두 옵션 결과에 대한 부울 AND 연산을 수행한다.
$ lsof -p $$ -a -d 1,2,3
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 715610 vagrant 1u CHR 136,2 0t0 5 /dev/pts/2
bash 715610 vagrant 2u CHR 136,2 0t0 5 /dev/pts/2
# '$$' 특수한 환경 변수로 현재 프로세스의 PID를 가리킨다.
| 열 | 설명 |
|---|---|
| COMMAND | 프로세스 안에 있는 명령 공정에서의 명령어 이름의 첫 아홉 글자 |
| PID | 프로세스 PID |
| USER | 프로세스를 소유한 사용자의 로그인 이름 |
| FD | 파일 디스크립터 번호 및 접근 유형 [r-(읽기), w-(쓰기), u-(읽기/쓰기)] |
| TYPE | 파일의 유형 [CHR-(글자), BLK-(블록), DIR-(디렉토리), REG-(일반 파일)] |
| DEVICE | 장치의 번호(majon, minor) |
| SIZE | 파일의 크기 |
| NODE | 로컬 파일의 노드 번호 |
| NAME | 파일의 이름 |
출력 버리기
널 파일은 이름 그대로 아무 것도 포함하지 않은 파일이다. 쉘이 널 파일로 보내는 모든 출력은 저장되지 않으며 따라서 없어진다.
리눅스 시스템에서 널 파일의 표준 위치는 /dev/null이다. 이곳으로 리다이렉트되는 모든 데이터는 없어지고 표시되지 않는다.
/dev/null 파일은 입력 리다이렉트에 입력 파일로도 사용할 수 있다. /dev/null 파일이 아무것도 포함하고 있지 않기 때문에 기존 파일의 데이터를 없애버리기 위해 이 방법을 사용할 수 있다.
$ echo "this is test message" > /dev/null
$ cat testline
This is the first line
This is the second line
This is the third line
$ cat /dev/null > testline
$ cat testline
메시지 로깅
- 출력을 모니터와 로그 파일에 모두 보내는 것이 도움이 될 수 있다. 출력을 두 번 리다이렉트하는 대신
tee명령을 사용할 수 있다. tee명령은 STDIN의 데이터를 동시에 두 개의 목적지로 보낸다. 한 가지 대상은 STDOUT이다. 또 다른 대상은tee커맨드라인에 지정된 파일 이름이다.tee명령은 STDIN에서 데이터를 리다이렉트하기 때문에 파이프 명령과 함께 사용하면 어떤 명령에서 나온 출력이든 이를 리다이렉트할 수 있다.- 출력은 STDOUT에 나타나고 지정된 파일에도 기록된다. 주의할 점은
tee명령의 기본 값은 사용할 때마다 출력 파일에 덮어쓰기를 하는 것이다. - 파일에 데이터를 추가하려면
-a옵션을 사용해야 한다.
# tee
$ date | tee date.txt
2023. 02. 13. (월) 20:55:44 KST
$ cat date.txt
2023. 02. 13. (월) 20:55:44 KST
# Overwrite
$ w | tee date.txt
20:56:27 up 14:25, 0 users, load average: 2.20, 1.51, 1.38
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
$ cat date.txt
20:56:27 up 14:25, 0 users, load average: 2.20, 1.51, 1.38
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
# -a option
$ date | tee -a date.txt
2023. 02. 13. (월) 20:57:44 KST
$ cat date.txt
20:56:27 up 14:25, 0 users, load average: 2.20, 1.51, 1.38
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
2023. 02. 13. (월) 20:57:44 KST
📖출처
리처드 블룸, 크리스틴 브레스, ⌜리눅스 커맨드라인 쉘 스크립트 바이블⌟, 스포트라잇북(2016)
👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄
댓글남기기