쿼카러버의 기술 블로그

Linux Shell Script - Pipe ( | ) (리눅스에서 파일 검색법, cpu 모델명 찾기 등) 쉬운 사용법 & 원리에 대한 이해 본문

Linux - Ubuntu/Shell Script

Linux Shell Script - Pipe ( | ) (리눅스에서 파일 검색법, cpu 모델명 찾기 등) 쉬운 사용법 & 원리에 대한 이해

quokkalover 2021. 7. 18. 15:59

타겟 :

  • 디렉토리 내에서 특정 파일이 있는지 확인하고 싶은 경우
  • pipe에 대한 개념 이해가 필요한 경우

등을 고민하는 분은 이 글을 참고하시기 바랍니다.

 

읽는법 :

쉬운 사용방법만 알고 싶은 분들은 Easy Explanation파트를,

왜?How?등 디테일하게 알아보고 싶다면 하단의 Pipe in Detail 참고.

 

 

Easy Explanation

pipe란?

"connect" one standard stream (usually stdout) of one process to standard stream of another process (usually stdin) via pipe.

  • 프로세스 혹은 실행된 프로그램, 명령어 등의 결과를 다른 프로그램으로 넘겨줄 때 사용
  • 헷갈리는 주의 사항: pipe는 순서를 보장하지 않음
    • command1 | command2이렇게 실행했다고, command1이 실행이 끝나야 command2로 넘어가는게 아니라 concurrent하기 작동함.

예: 명령어의 결과(ls *)를 grep "name" 에 넘기기

= 현재 디렉토리에 있는 파일명들 중에 "name"이 들어간게 있으면 출력하기

ls * | grep "name"

예시들

예1) 특정 디렉토리에서 파일 찾기

ls * | grep "name"

예2) cpu 모델 이름 찾기

cat /proc/cpuinfo | grep "model name"

예3) hard disk 장비의 이름 출력하기

dmesg | egrep '(s|h)d[a-z]'

예4) 특정 파일 정보중에 원하는 부분만 출력하기

cat sample2.txt | head -7 | tail -5

예5) 디렉토리 내에서 특정 패턴을 내용으로 가지고 있는 파일이 있는 경우 해당 line을 출력

$ ls -l | find ./ -type f -name "*.txt" -exec grep "program" {} \;
  • 위를 실행하면 해당 디렉토리에서 .txt 확장자명을 가진 파일을 찾아서 program이라는 단어를 내용물로 담고 있으면, 해당 라인을 출력함.

 

Pipe in Detail

pipe란?

"connect" one standard stream (usually stdout) of one process to standard stream of another process (usually stdin) via pipe.

  • 프로세스 혹은 실행된 프로그램, 명령어 등의 결과를 다른 프로그램으로 넘겨줄 때 사용
  • 위 그림으로 설명하면 Program1명령어의 출력을 Program2의 입력으로 연결하고, Program2의 출력을 Program3의 입력으로 연결

예: 명령어의 결과(ls *)를 grep "name" 에 넘기기

= 현재 디렉토리에 있는 파일명들 중에 "name"이 들어간게 있으면 출력하기

ls * | grep "name"

 

IPC의 한 형태

파이프는 IPC (Inter Process Communication)의 한 방법이다.

  • 쉘 커맨드에서 명령어들은 각각 독립적인 주소공간을 갖는 프로세스들이다.
  • 즉, 한 프로세스가 다른 프로세스의 정보를 알 수는 없음.
  • 프로세스들간에 정보를 전달하기 위해서 IPC 방법을 사용하는데, shell에서는 파일을 이용할 수 있다.
  • 파이프를 통해 전달되는 데이터는 단순 byte stream이다.

 

모듈 프로그래밍

파이프를 이용하면 터미널 창에서 모듈 프로그래밍을 할 수 있다.

, 문자로 구분된 필드를 가진 txt파일에서 3번째 필드를 선ㄴ택하여 그 중 첫 자가 c로 시작하는 항목들만 뽑아내어 알파벳 순으로 정렬하기

cat inventory.txt | cut -d ',' -f 3 | grep '^c' | sort
  • 필요한 명령어를 고르고 적절한 옵션을 준 후에 파이프로 연결하면 프로그래밍을 한 것처럼 좋은 결과를 만들어낼 수 있다.
  • 파이프 ⇒ 각기 독립적인 역할을 하는 프로그램을 만들고, 필요에 따라 조합하여 전체를 완성하는 것

 

subshell

  • 파이프로 연결된 명령은 subshell에서 실행된다.

아래는 프롬프트 상에서

 { echo; sleep 10 ;} | { echo; sleep 10 ;} | { echo; sleep 10 ;} 

명령을 실행했을때의 프로세스 상태인데 파이프로 연결된 세 명령 모두 subshell 이 생성된후에 그 아래에서 실행되는것을 볼 수 있다.

그러므로 마지막 명령에서 결과를 어떤변수에 저장한다면 그값은 파이프 실행이 종료되면 사라지게 된다.

 

파이프로 연결된 명령들은 순서대로 실행될까?

보통 파이프에 대해 설명할때 command1 | command2 가 있을경우 command1의 실행결과가 command2 의 입력으로 들어간다고 말한다.

그렇다면 command1 이 종료된 후에 command2 가 실행될것 같지만 실은 그렇지 않다.

$ ps | grep ".*"
PID TTY          TIME CMD
3773 pts/0    00:00:00 bash
3784 pts/0    00:00:00 ps
3785 pts/0    00:00:00 grep
  • 위에서 ps를 실행했을 때, ps실행이 종료돼야 grep이 실행된다면 결과물에 grep이 포함되선 안된다.
  • 즉, 파이프로 연결된 프로글매들은 순서대로 실행되지 않고, 동시에 실행되며, 또한 command2의 상태에 따라 command1의 실행이 완료되기전에 종료할 수 있다.

[ 결과적으로 cmd1 | cmd2 와 같이 명령이 실행될 경우 ]

  1. cmd1cmd2 는 동시에 병렬로 실행된다.
  2. cmd1cmd2 보다 빠르면 파이프에 write 은 블록되고 더이상 진행되지 않는다.
  3. cmd2cmd1 보다 빠르면 파이프 로부터의 read 는 블록된다.
  4. cmd1 이 먼저 종료하면 파이프는 close 되고 cmd2 는 End-Of-File 로 인식해 종료한다.
  5. cmd2 가 먼저 종료하면 파이프는 close 되고 cmd1 은 다음번 write 에 SIGPIPE 신호를 받게되고 종료된다.

 

파이프로 연결된 명령들은 process group 을 형성한다.

파이프를 이용해 여러 명령들을 동시에 실행시키면 process group 이 만들어지는데 이때 파이프로 연결된 명령들 중에서 첫 번째 명령의 PID 가 Process Group ID (PGID) 가 된다.

이후 jopspec 을 이용해 job control 을 하게 되면 동일한 process group 에 속한 명령들이 모두 같이 적용을 받게 된다.

다음은 프롬프트 상에서 $ cat | grep hello | wc -l 명령을 실행한 예입니다

 

background 프로세스 와 파이프

첫 번째로 background 프로세스의 특징은 parent 프로세스가 종료될 때까지 기다리지 않는다는다.

따라서 다음과 같은 코드가 실행될 경우 메인 프로세스는 차례로 3 개의 명령을 background 로 실행 시킨 후에 바로 종료하게 된다.

background 프로세스들은 parent 프로세스의 설정에 따라 stdout 이 모두 outfile 파일로 연결되어 명령 실행 결과를 출력한다.

{
    command1 &
    command2 &
    command3 &
} > outfile

두 번째로 파이프의 특징은 파이프 양쪽의 프로세스들이 서로 연결된 상태에서 그룹으로 하나의 명령처럼 실행된다.

따라서 코드를 조금 바꾸어 아래와 같이 실행하게 되면 3 개의 background 프로세스들과 cat 명령은 서로 파이프로 연결된 상태가 되고, cat 명령은 현재 메인 프로세스에 속하므로 결과적으로 background 프로세스들이 모두 종료될 때까지 메인 프로세스도 종료되지 않게 된다.

{
    command1 &
    command2 &
    command3 &
} | cat > outfile

 

번외

redirection으로도 piping과 비슷한 기능을 수행할 수는 있음

A의 출력을 B로 건내주고 싶을 때

A > temp_file && B < temp_file
  • 하지만 오타 입력하거나, 동일한 파일 이름 존재하거나 할 때 예상하지 못한 오류발생 가능

참고자료

https://mug896.github.io/bash-shell/pipe.html

Comments