[쉘 스크립트] 쉘 스크립트 기초 - 데이터 보여주기 (5)

업데이트:     Updated:

카테고리:

태그:

표준 출력, 표준 에러 리다이렉트

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)


👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄

맨 위로 이동하기

Linux 카테고리 내 다른 글 보러가기

댓글남기기