Profile picture

[Shell Script] 입출력 재지정 & 파이프라인 정리

JaehyoJJAng2023년 04월 24일

리다이렉션 ?

쉘에서 키보드로 명령을 입력받는 것을 표준 입력(Standard Inupt)이라 하며, 키보드로 입력 받은 명령의 실행결과를 모니터로 출력하는 것을 표준 출력(Standard Outpu)이라고 합니다.

image


입출력 리다이렉션

리다이렉션 기호 방향 의미
> 표준 출력 명령 > 파일 : 명령의 결과를 파일로 저장
>> 표준 출력 명령 >> 파일 : 명령의 결과를 기존 파일 데이터에 추가
< 표준 입력 명령 < 파일 : 파일의 데이터를 명령에 입력

기타 리다이렉션

기호 의미
명령 >& 파일명 명령이 실행된 표준 출력의 결과와 에러를 파일로 출력
명령 >>& 파일명 명령이 실행된 표준 출력의 결과와 에러를 파일로 덧붙여 출력
명령 >| 파일명 파일의 존재 유무와 상관없이 파일을 생성하고 명령의 출력을 파일에 덮어쓰기로 저장하는 것을 강제함
명령A |& 명령B 명령A의 출력과 에러를 명령 B의 입력으로 사용하여 실행

기타 리다이렉션 예시

>& 리다이렉션 예시

$ ls /nonexistent_directory 1> log.out 2>&1

표준 에러를 표준 출력으로 리다이렉션


|& 리다이렉션 예시

grep "error" log.txt |& grep "fatal"

위의 예시에서, log.txt 파일에서 "error" 라는 키워드를 찾는 'grep' 명령의 출력과 에러를 'grep "fatal"' 명령의 입력으로 사용하여 실행합니다.

이렇게 함으로써 log.txt 파일에서 "error"와 "fatal"이라는 키워드를 동시에 찾아내고자 할 때 유용합니다.

'명령A'의 출력과 에러를 동시에 다른 명령에 전달하여 처리할 수 있습니다.

리다이렉션 활용

자주 사용되는 리다이렉션 활용한 예시

>

  • 출력 리다이렉션
  • 왼쪽 명령어의 출력 결과를 오른쪽 파일에 덮어씀
  • 만약 파일이 존재하지 않으면 새롭게 파일을 생성
$ ls > file.txt

>>

  • 출력 리다이렉션 (append)
  • 왼쪽 명령어의 출력 결과를 오른쪽 파일에 추가
  • 만약 파일이 존재하지 않으면 새롭게 파일을 생성
$ echo "Hello" > file.txt

$ cat file.txt
Hello

$ echo "Bye" >> file.txt
Hello
Bye

>|

  • 강제 출력 리다이렉션
  • 파이프 라인을 강제로 덮어쓰기 위해 사용

보통, 리눅스에서 파이프 라인은 두 개의 명령어를 연결하여, 첫 번쨰 명령어의 출력을 두 번쨰 명령어의 입력으로 전달

ls | grep txt

위 명령어는 ls로부터의 출력을 grep 'txt' 명령어의 입력으로 전달

하지만 경우에 따라서 첫 번째 명령어가 출력을 파이프라인을 통해 전달하지 않도록 하기 위해 >| 리다이렉션 기호가 사용됨.

해당 리다이렉션 기호를 사용하면 두 번째 명령어가 실행되기 전 먼저 첫 번째 명령어의 출력이 덮어써지므로, 첫 번째 명령어의 출력이 파이프 라인을 통해 전달되지 않음

또는

파일의 존재 유무와 상관없이 파일을 생성하고 명령의 출력을 파일에 덮어쓰기로 저장하는 것을 강제합니다.

이는 파일의 존재 여부와 관계없이 명령의 출력을 덮어쓰기로 저장하는 것을 보장하며, 기존 파일의 내용을 무시하고 새로운 내용으로 덮어쓰기를 수행합니다.

Ex

$ echo "Hello"; echo "Bye" >| bye.txt
$ cat bye.txt

Bye

<

  • 입력 리다이렉션
  • 오른쪽 파일의 내용을 왼쪽 명령어의 입력으로 사용

$ sort < unsorted.txt > sorted.txt

unsorted.txt 파일의 내용을 sort 명령의 입력으로 사용하고 정렬된 결과를 sorted.txt 파일에 저장한다

<<

  • 스크립트에서 여러 줄에 걸친 입력을 처리하는 방법
  • 입력을 구분하는 문자열을 명시하고, 해당 문자열이 나오기 전까지 입력을 받음

cat << EOF > document.txt
여기에 내용을 적으세요
그리고 내용을 다 적고 마지막에 EOF로 마무리하세요
EOF

cat 명령어를 사용하여 EOF 문자열이 나오기 전까지 입력된 여러 줄의 텍스트를 출력하고 출력된 결과를 document.txt 파일에 저장한다

<<<

  • 스크립트에서 단일 문자열을 명령어의 입력으로 사용하는 방법
  • 문자열을 따옴표로 감싸지 않아도 된다

$ grep -i "keyword" <<< "This is a text containing keyword"

grep 명령어를 사용하여 'This is a text containing keyword' 문자열에서 'keyword' 를 대소문자 구분 없이 검색

&1>

  • 표준 출력을 파일로 리다이렉션

command &>1 new_file.txt

command의 표준 출력이 new_file.txt 파일로 리다이렉션 된다

&>

  • 표준 출력과 표준 에러를 모두 파일로 리다이렉션

command &> file.txt

command의 표준 출력과 표준 에러가 모두 file.txt 파일로 리다이렉션 된다


필요에 따라서는

command &1> success.log 2> error.log

위처럼 리다이렉션을 따로 사용해야 할 수도 있다

이유는 표준 출력과 표준 에러가 한 파일에 혼재되어 저장되기 때문에!

2>&1

  • 표준 에러 출력을 표준 출력으로 리다이렉션
    • 2> : 표준 에러 출력 의미
    • &1 : 표준 출력 의미

명령어 실행 결과와 에러 메시지를 동시에 확인하고자 할 때 유용


$ bash build.sh 1>/dev/null 2>&1

2>&1 리다이렉션을 보면 궁금한 점이 생길 수도 있다.

명령 >& 파일명 이 리다이렉션도 표준 출력의 결과와 에러를 파일로 출력하는데

2>&1 리다이렉션과 다를게 무엇인지? 그리고 왜 2>&1 리다이렉션을 실무에서 더 많이 사용하는지?


exec

exec는 셸에서 사용되는 내장 명령어로, 파일 디스크립터를 조작하고 리다이렉션을 수행하는 데에 사용된다.
exec 를 사용하면 새로운 명령 실행을 위해 현재 프로세스를 대체할 수 있다


a. 파일 디스크립터를 리디렉션하여 파일에 쓰기

exec 1> output.txt
echo "This will be written to the file"

위의 예제에서 exec 1> output.txt는 파일 디스크립터 1(표준 출력)을 output.txt 파일에 쓰기 위해 리다이렉션 한다.
따라서 echo 명령어의 출력은 output.txt 파일에 저장된다


b. 파일 디스크립터를 닫기

exec 3>&-
echo "This will generate an error" >&3

위의 예제에서, exec 3>&-는 파일 디스크립터 3을 닫는다. 따라서 >&3으로 표준 오류를 파일 디스크립터 3으로 리디렉션하는 echo 명령어는 오류를 발생시킴


c. exec으로 파일디스크립터 활용

#!/bin/bash

CF='./world-writable.txt'

exec 3>> "${CF}"
echo "1. world writable 파일 점검"
echo "2. world writable 파일 점검" >&3
  • CF='world-writable.txt': 변수 CF를 선언하고 값을 'world-writable.txt'로 설정함. 이 변수는 파일명을 저장하는 용도로 사용된다
  • exec 3>> "${CF}": 파일 디스크립터 3을 파일 ${CF}에 대한 쓰기 권한을 가지도록 연다는 의미. ${CF}는 이전에 설정된 world-writable.txt 파일을 가리킴.따라서 파일 디스크립터 3은 해당 파일을 쓰기 위해 열려 있음.
  • echo "1. world writable 파일 점검": 텍스트 "1. world writable 파일 점검"을 표준 출력으로 출력.
  • echo "2. world writable 파일 점검" >&3: 텍스트 "2. world writable 파일 점검"을 파일 디스크립터 3으로 리디렉션하여 파일 ${CF}에 쓰도록 함. 이렇게 하면 "2. world writable 파일 점검"이 ${CF} 파일에 추가된다

즉, 이 스크립트는 ${CF} 파일을 열어서 파일 디스크립터 3으로 사용한 후, 첫 번째 echo 구문은 표준 출력으로 출력하고, 두 번째 echo 구문은 파일 ${CF}에 추가하는 역할을 수행함



파이프

파이프라는 것은 program1의 표준 출력을 program2의 표준입력으로 입력받는 것이다!

즉, 명령어의 결과를 다시 어떤 명령어의 입력으로 받아야 할때 사용된다

🚦 TIP


요약: 앞 명령어의 결과를 뒤에 나오는 명령어의 입력으로 처리할 때 사용하는 방법이다

  • 둘 이상의 명령을 함께 묶어 출력의 결과를 다른 프로그램의 입력으로 전환 하는 기능
  • 즉, 명령어의 표준 출력을 또 다른 명령어의 표준 입력과 연결
  • 명령어와 명령어의 연겷은 | 기호를 사용한다
  • | 기호 앞의 명령결과가 뒤의 명령에 입력 데이터로 사용된다

표준 입력 예제 1

# PROGRAM1의 표준 출력을 PROGRAM2의 표준 입력으로 입력 받는다
$ PROGRAM1 | PROGRAM2 

표준 입력 예제 2

# 디렉토리 개수 확인하기
$ ll | grep -v "total" | wc -l

# * ll = ls -l : List 형태로 출력
# * grep -v "total" : total 행 제외
# * wc -l : 행의 개수 출력

표준 입력 예제 3

# yes 출력을 docker system prune 명령어의 입력으로 넘김
# docker system prune 명령어 사용 시 정말로 정리할거냐고 물어보는 항목이 있는데 
# 아래 명령어처럼 사용하면 해당 항목에 대해 yes가 입력으로 넘어가기 때문에 
# 스크립트 파일에서 유용하게 사용할 수 있음
$ yes | docker system prune

Loading script...