쉘스크립트

데이터 표현하기

트리스탄1234 2022. 7. 6. 08:52
728x90
반응형

 

1. 입력과 출력 이해하기

지금까지 데이터의 출력은 모니터로 보내거나 또는 파일로 보내거나를 진행해 보았습니다. 하지만 가끔은 특정 데이터는 모니터로 보내고, 특정 데이터를 파일로 보내고 싶은 경우가 있을겁니다. 그럼 지금부터 스크립트에서 어떻게 그렇게 사용할수 있는지 알아 보도록 하겠습니다.

표준 파일 디스크립터

리눅스 시스템은 모든 객체를 파일로 취급을 합니다. 출력과 입력도 모두 파일로 처리가 되는데요. 이 파일 디스크립터는 음이 아닌 정수이고 하나의 세션에서 최대 9개의 파일 디스크립터를 열수 있습니다. bash shell에서는 첫번째 부터 3개의 파일 디스크립터를 예약을 해놓고 있습니다. (0번, 1번, 2번)

STDIN

표준 입력 파일 디스크립터는 shell로의 표준 입력값을 참조 합니다. shell로의 기본 입력은 keyboard이므로 shell은 STDIN 파일 상에서 키보드 입력값을 받고 처리를 합니다. 입력 리다이렉트를(<) 사용을 하면 표준 입력이 키보드에서 언급된 파일로 바뀌게 됩니다. 아래 표는 표준 파일 디스크립트를 설명하는표 입니다.

STDERR

shell은 STDERR 파일 디스크립터를 통해 메세지를 처리하게 됩니다. STDERR은 에러 메세지를 출력하는 위치를 가르키는데요. 기본적으로는 stdout과 동일하게 모니터로 보냅니다. 다만 필요에 따라 리다이렉트로 다른곳으로 출력 하게 할수 있습니다.

에러 리다이렉트 하기

위의 표에서 보듯이 stderr의 파일 디스크립트는 2번 입니다. 그럼 에러만 리다이렉트를 할경우 이 번호를 이용하여 아래와 같이 리다리게트가 가능 합니다.

$ ls -al tttfile 2>rrr
$ cat rrr
ls: 'tttfile'에 접근할 수 없습니다: 그런 파일이나 디렉터리가 없습니다
$

2. 스크립트에서 출력 리다이렉트 하기

STDOUT과 STDERR 파일 디스크립트는 스크립트안에서 명령어 출력의 위치를 여러개로 만들수 있습니다.

■ 임시적으로 각각의 라인을 임시 위치로 리다리렉트 가능

■ 스크립트 안에서 모든 명령어의 결과를 영구적으로 다른 위치로 리다이렉트 가능

임시 리다이렉트

특정 메세지를 STDERR로 리다이렉트를 할때에는 &기호를 사용해야 합니다.

아래 예제를 한번 봅시다.

#! /bin/bash
#STDERR 메세지 임시 리다이렉트 하기
echo "this is an error" >&2 ==> echo로 표시되는 메세지를 stderr로 리다이렉트
echo "this is normal output"

실핼을 시켜 보면 일반 출력문과 다르지 않습니다. 그 이유는 기본적으로 STDERR은 STDOUT의 출력 위치와 동일 합니다.

$ ./test6
this is an error
this is normal output

아래와 같이 스크립트를 실행시킬때 STDERR을 리다이렉트를 시켜 보면 에러값만 다른 파일에 저장됨을 볼수 있습니다.

$ ./test6 2> test7
this is normal output
$ cat test7
this is an error
$

영구 리다이렉트

리다이렉트할 데이터가 많은 경우 매 라인마다 echo를 통해 리다이렉트를 하기가 매우 번거럽 습니다. 이를 편하게 해주는 명령어로 exec명령이 있습니다. 아래의 스크립트와 실행결과를 살펴 봅시다.

#! /bin/bash
# 영구 리다이렉트 하기
exec 1>test9 ===> exec 명령을 통해 이 스크립트의 실행 결괄르 모두 test9으로
echo "test test test"
echo "hello test hello"
echo "redirect redirec redirect"
해당 스크립트를 실행을 해보면
$ ./test8
$ cat test9
test test test
hello test hello
redirect redirec redirect

3. 스크립트에서 입력을 리다이렉트 하기

사용 방법은 위의 STDOUT과 STDERR과 동일 합니다. 아래와 같이 스크립트를 통해 살펴 보겠습니다.

#! /bin/bash
#입력 리다이렉트 테스트 하기
exec 0<testinput ==> testinput 파일로 부터 데이터 입력 받기.
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
실행을 시켜 보면
$ ./testredirect
Line #1:
Line #2: seoul is beautiful city
Line #3: daegu is so hot
Line #4: busan is beautiful beach city
Line #5:
Line #6:
$

4. 사용자 정의 리다이렉트 사용하기

위에서 언급을 하였듯이 shell에서 사용가능한 파일 디스크립터는 총 9개 입니다. 그중 3개는 표준 파일 디스크립트 이고 나머지(3번 ~ 8번)까지는 사용자가 임의로 지정하여 사용을 할수가 있습니다.

아래의 예제를 통해 사용자 정의 리다이렉트를 사용하는 예제를 살펴 보도록 하겠습니다.

출력 리다이렉트

#! /bin/bash
#사용자 정의 파일 디스크립터 이용하기
exec 3>test20 ==> 파일디스크립터 3은 test20파일 안으로
echo "this is test to display monitor" ==> STDOUT인 모니터로 출력
echo "and this is belongs to file" >&3 ==> 파일 디스크립트 3인 test20으로 저장
echo "this is diaplyed in monitor" ==> 모니터로 출력
실행을 해보면
$ ./test10
this is test to display monitor
this is diaplyed in monitor
$ cat test20
and this is belongs to file
$

사용자 파일 디스크립트로 리다이렉트 하기.

#!/bin/bash
# storing STDOUT, then coming back to it
exec 3>&1 ===> 파일 디스크립터 3일 표준 출력 1로 리다이렉트
exec 1>test14out ===> 표준 출력 리다이렉트를 test14out 파일로
echo "This should store in the output file" ==> 표준 출력이 파일로 되어 있으므로 파일에 저장
echo "along with this line." ==> 이것도 파일로 저장
exec 1>&3 ==> 표준출력을 3번 파일 디스크립트로 리다이렉트(모니터)
echo "Now things should be back to normal"
실행을 해보면
$ ./test14
Now things should be back to normal
$ cat test14out
This should store in the output file
along with this line.
$
반응형

입력 리다이렉트하기

#!/bin/bash
# redirecting input file descriptors
exec 6<&0 ==> 표준 입력을 파일디스크립터 6번으로
exec 0< testfile ==> 표준 입력을 파일로 부터 읽어 들이기.
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
exec 0<&6 ==> 파일 디스크립터 6번을(키보드) 표준 입력 0번으로
read -p "Are you done now? " answer
case $answer in
Y|y) echo "Goodbye";;
N|n) echo "Sorry, this is the end.";;
esac
실행을 시키면.
$ ./test15
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
Are you done now? y
Goodbye
$

읽기/쓰기 파일 디스크립터 사용하기

#!/bin/bash
# testing input/output file descriptor
exec 3<> testfile ==> testfile에 파일 디스크립트 3을 통해 입력 출력을 받게 지정
read line <&3 ==> 파일에서 첫번째 라인을 읽어 들입니다.
echo "Read: $line" ==> 읽어 들인 첫번째 라인을 STDOUT을 통해 모니터로 출력
echo "This is a test line" >&3 ==> echo 문의 출력 결과를 파일 디스크크립터 3으로 testfile에 저장
$ cat testfile
This is the first line.
This is the second line.
This is the third line.
실행을 시켜 보면
$ ./test16
Read: This is the first line.
$ cat testfile
This is the first line.
This is a test line
ine.
This is the third line.
$

파일 디스크립터 닫기

입출력 파일 디스크립트를 만들면 shell은 스크립트가 종료될때 파일 디스크립트도 자동으로 종료를 시킵니다. 자동적으로 종료 되지 않고 스크립트 실행 중에 수동으로 종료 시키고 싶은 경우에는 exec 3>&와 같이 파일 디스크립트를 &로 리다이렉트 시키면 종료가 됩니다.

#!/bin/bash
# testing closing file descriptors
exec 3> test17file ===> 3번의 출력을 test17file로 리다이렉트
echo "This is a test line of data" >&3 ===> test17file에 echo문 저장
exec 3>&- ===> 파일 디스크립터 3번 종료
echo "This won’t work" >&3 ===> 3번으로 출력 저장
실행을 시켜 보면
$ ./badtest
./badtest: 3: Bad file descriptor
$

스크립트 안에서 파일 디스크립트를 종료 시키고 다시 사용하는 예제를 살표 보겠습니다.

#!/bin/bash
# testing closing file descriptors
exec 3> test17file ==> 파일 디스크립 3을 test17file로 리다이렉트
echo "This is a test line of data" >&3 ==> echo의 실행문을 test17file로 저장
exec 3>&- ==> 파일 디스크립트 3번 종료
cat test17file
exec 3> test17file ==> 파일 디스크립터 3번을 다시 test17file로 리다이렉트
echo "This’ll be bad" >&3 ==> test17file에 echo구문을 덮어 쓰기.
$ ./test17
This is a test line of data
$ cat test17file
This’ll be bad
$

5. 열려 있는 파일 디스크립트 표시 하기.

사용자 정의 파일 디스크립트 중에서 현재 열려 있는 파일 디스크립트를 조회 하고 싶은경우에는 lsof 명령을 사용을 하면 됩니다. lsof를 입력을 해보면 현재 리눅스에 열려 있는 모든 파일과 백그라운드로 실행되고 있는 프로세스 그리고 시스템에 로그인 되어 있는 사용자 정보를 보여 줍니다. 하지만 파일 디스크립트만 보고자 하는 경우에는 아래의 옵션들고 같이 사용하면 됩니다.

-a : 두개의 옵션들의 결과를 AND 연산을 합니다.

-p : 특정 PID를 지정할때 사용하는 옵션 입니다. 현재 사용하고 있는 PID를 사용을 할때에는 $$ 기호를 사용하면 됩니다.

-d : 파일 디스크립트를 지정할때 사용합니다.

아래는 현재 사용하는 pid의 파일 디스크립트 0,1,2번을 같이 출력을 해주는 예제 입니다.

$ lsof -a -p $$ -d 0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 11246 hyowon 0u CHR 136,2 0t0 5 /dev/pts/2
bash 11246 hyowon 1u CHR 136,2 0t0 5 /dev/pts/2
bash 11246 hyowon 2u CHR 136,2 0t0 5 /dev/pts/2

위의 출력물의 각 필드에 대한 설명은 아래와 같습니다.

6. 명령어 출력 결과 줄이기

백그라운드로 실행되는 프로세스나 사용자가 에러 메세지를 표시 하지 않기를 원하는 경우 STDERR을 NULL파일로 리다이렉트를 하면 출력결과를 줄일 수가 있습니다.

아래의 몇가지 예제를 살펴 보겠습니다.

$ ls -al > /dev/null ====> ls 명령의 결과를 /dev/null로 리다이렉트
$ cat /dev/null
$
$ cat testfile ===> testfile의 내용을 봅니다.
This is the first line.
This is the second line.
This is the third line.
$ cat /dev/null > testfile ===> dev/null을 testfile의 입력으로 리다이렉트 합니다.
$ cat testfile ===> 파일의 내용이 다 지워 졌음을 알수 있습니다.
$

7. 임시 파일 이용하기

리눅스는 임시 파일을 위한 틀별한 디렉토리를 제공 합니다. /tmp 디렉토리 입니다. 리눅스 시스템들은 리부팅을 할때 /tmp에 있는 파일들을 자동적으로 모두 삭제 합니다. 임시 파일을 생성하고 싶을때에는 mktemp 명령을 사용하여 파일을 생성하면 생성되는 파일들은 umask가 적용이 되지 않고 읽기와 쓰기 권한을 생성자에게 부여를 하고 다른 사용자는 접속을 할수 없습니다.

임시파일 생성하기

임시 파일을 생성하는 방법은 파일 이름과 뒤에 여섯개의 X 문자를 지정을 하면 됩니다

$mktemp testing.XXXXXX
$ ls -al testing*
-rw------- 1 rich rich 0 Oct 29 21:30 testing.UfIi13
$

하나의 스크립트를 더 살펴 보겠습니다.

#! /bin/bash
# temp 파일 사용 예제
tempfile=`mktemp test21.XXXXXX` ===> mktemp를 사용해서 임시 파일 생성
exec 3>$tempfile ===> 파일 디스크립터 3을 tempfile로 리다이렉트
echo "this script writes to temp file $tempfile"
echo "This is the fiest line" >&3 ===> tempfile에 echo문 저장
echo "This is the second line" >&3
echo "This is the last line" >&3
exec 3>&- ===> 파일 디스크립트 3 종료
echo "Donw creating tempfile the contents are:" ===>모니터로 echo 문 출력
cat $tempfile ===> tempfile의 내용을 출력
rm -f &tempfile 2> /dev/null ===> stderr을 null로 버림.
실행을 해보면
$ ./test20
this script writes to temp file test21.qwUPhy
Done creating tempfile the contents are:
This is the fiest line
This is the second line
This is the last line
/tmp/fileQL0qjI

/tmp 밑에 입시 파일 생성하기

-t 옵션은 mstemp로 생성되는 파일을 /tmp파일에 생성을 시킵니다. -t 옵션으로 생성되는 파일명은 사용자가 지정해준 파일 이름과 앞에 경로가 추가되어 전체 파일 이름이 된다.

$ mktemp -t test.XXXXXX
/tmp/test.xG3374
$ ls -al /tmp/test*
-rw------- 1 rich rich 0 2007-10-29 18:41 /tmp/test.xG3374

 

사용 예제를 하나 봅시다.

#!/bin/bash
# creating a temp file in /tmp
tempfile=`mktemp -t tmp.XXXXXX`
echo "This is a test file." > $tempfile
echo "This is the second line of the test." >> $tempfile
echo "The temp file is located at: $tempfile"
cat $tempfile
rm -f $tempfile
#
실행을 시켜 보면
$ ./test20
The temp file is located at: /tmp/tmp.Ma3390
This is a test file.
This is the second line of the test.
$

임시 디렉토리 만들기

-d 옵션은 임시 디렉토리를 만들때 사용 합니다. 이 임시 디렉토리도 /tmp와 마찬가지로 리부팅 하면 사라 집니다.

그럼 예제를 하나 보겠습니다.

#!/bin/bash
# using a temporary directory
tempdir=`mktemp -d dir.XXXXXX` ==> 임시 디렉토리를 만듭니다.
cd $tempdir ==> 임시 디렉토리로 이동
tempfile1=`mktemp temp.XXXXXX` ==> 임시 파일을 생성
tempfile2=`mktemp temp.XXXXXX` ==> 임시 파일을 생성
exec 7> $tempfile1
exec 8> $tempfile2
echo "Sending data to directory $tempdir" ==> 임시 파일의 위치를 표시
echo "This is a test line of data for $tempfile1" >&7 ==> 임시 파일로 echo문장 저장
echo "This is a test line of data for $tempfile2" >&8 ==> 임시 파일로 echo문장 저장

8. 로깅 메세지

가끔은 로깅 메세지를 모니터와 파일로 저장을 해야 하는 경우가 있습니다 이경우 redirect하는것 말고 가능하게 하는 명령이 있습니다. tee명령을 사용을 하면 됩니다. 명령어 사용 구문은 아래와 같이 사용을 하면 됩니다.

tee명령을 사용하면 그 결과는 모니터와 지정한 파일에 전달이 됩니다.

tee filename

$ date | tee testfile
Mon Oct 29 18:56:21 EDT 2007
$ cat testfile
Mon Oct 29 18:56:21 EDT 2007
$
tee명령은 실행을 할때 마다 출력을 파일에 엎어쓰기를 합니다. 만약 엎어 쓰기가 아니고 추가 하고 싶은 경우에는 아래의 예제처럼 사용하면 됨니다.
$ date | tee -a testfile
2021. 06. 15. (화) 16:22:55 KST
$ cat testfile
2021. 06. 15. (화) 16:21:15 KST
2021. 06. 15. (화) 16:22:46 KST
2021. 06. 15. (화) 16:22:55 KST

이번 포스팅은 이만 마치겠습니다.

728x90
반응형

'쉘스크립트' 카테고리의 다른 글

함수 만들기  (1) 2022.07.06
스크립트 제어  (1) 2022.07.06
사용자 입력 데이터 처리  (1) 2022.07.06
세부 구조적인 Shell 명령어  (1) 2022.07.06
구조화된 명령어들  (1) 2022.07.06