bash에서 <<, <<< 및 <<의 차이점은 무엇입니까?


102

무슨 사이의 차이점 <<, <<<그리고 < <bash는?


20
적어도 구글 중심 시대에는 이러한 기호 기반 연산자를 검색하기가 어렵습니다. "<< <<< <<"를 연결하고 유용한 정보를 얻을 수있는 검색 엔진이 있습니까?
Daniel Griscom

11
@DanielGriscom있다 SymbolHound은 .
Dennis

1
@DanielGriscom Stack Exchange는 기호 검색을 지원하는 데 사용되었지만 문제가 발생하여 아무도 해결하지 못했습니다.
muru

이미 존재하고 있으며 거의 ​​1 년이 지났습니다 . 셸의 제어 및 리디렉션 연산자는 무엇입니까?
Scott

답변:


115

여기 문서

<<라고도 here-document구조. 종료 텍스트가 무엇인지 프로그램에 알리고 구분 기호가 표시 될 때마다 프로그램은 입력 한 모든 내용을 입력으로 읽고 작업을 수행합니다.

여기 내가 의미하는 바가있다 :

$ wc << EOF
> one two three
> four five
> EOF
 2  5 24

이 예제에서 우리는 wc프로그램에게 EOF문자열 을 기다렸다가 5 단어를 입력 한 다음 입력 EOF하여 입력을 완료했다는 신호를 보냅니다. 실제로 wc자체적 으로 실행 하고 단어를 입력 한 다음CtrlD

bash에서는 임시 파일을 통해 일반적으로 형식 /tmp/sh-thd.<random string>으로 구현되며 대시에서는 익명 파이프로 구현됩니다. 이것은 strace명령을 사용 하여 추적 시스템 호출을 통해 확인할 수 있습니다 . 교체 bashsh방법을 보려면 /bin/sh이 리디렉션을 수행합니다.

$ strace -e open,dup2,pipe,write -f bash -c 'cat <<EOF
> test
> EOF'

여기 문자열

<<<로 알려져 있습니다 here-string. 텍스트를 입력하는 대신 미리 만든 텍스트 문자열을 프로그램에 제공합니다. 예를 들어, 특정 사례에 대한 출력을 얻기 위해 bc할 수있는 프로그램을 사용 bc <<< 5*4하면 대화식으로 bc를 실행할 필요가 없습니다.

bash의 here-string은 임시 파일을 통해 일반적으로 형식화 /tmp/sh-thd.<random string>되어 나중에 연결이 해제되므로 일부 메모리 공간을 일시적으로 차지하지만 /tmp디렉토리 항목 목록에는 표시되지 않으며 익명 파일로 효과적으로 존재합니다. 쉘 자체에 의해 파일 디스크립터를 통해 참조되고, 파일 디스크립터는 명령에 의해 상속되고 나중에 dup2()함수 를 통해 파일 디스크립터 0 (stdin)에 복제 됩니다. 이것은 통해 볼 수 있습니다

$ ls -l /proc/self/fd/ <<< "TEST"
total 0
lr-x------ 1 user1 user1 64 Aug 20 13:43 0 -> /tmp/sh-thd.761Lj9 (deleted)
lrwx------ 1 user1 user1 64 Aug 20 13:43 1 -> /dev/pts/4
lrwx------ 1 user1 user1 64 Aug 20 13:43 2 -> /dev/pts/4
lr-x------ 1 user1 user1 64 Aug 20 13:43 3 -> /proc/10068/fd

그리고 (출력 가독성 단축 콜 추적을 통해, 임시 파일을 FD (3)에 쓸 데이터 그때는 재 개방으로 개방되는 방식을 통지 O_RDONLY한 후, FD 4로 플래그 나중에 해제 dup2()상속 FD 0에, cat나중에 ) :

$ strace -f -e open,read,write,dup2,unlink,execve bash -c 'cat <<< "TEST"'
execve("/bin/bash", ["bash", "-c", "cat <<< \"TEST\""], [/* 47 vars */]) = 0
...
strace: Process 10229 attached
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
[pid 10229] write(3, "TEST", 4)         = 4
[pid 10229] write(3, "\n", 1)           = 1
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDONLY) = 4
[pid 10229] unlink("/tmp/sh-thd.uhpSrD") = 0
[pid 10229] dup2(4, 0)                  = 0
[pid 10229] execve("/bin/cat", ["cat"], [/* 47 vars */]) = 0
...
[pid 10229] read(0, "TEST\n", 131072)   = 5
[pid 10229] write(1, "TEST\n", 5TEST
)       = 5
[pid 10229] read(0, "", 131072)         = 0
[pid 10229] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=10229, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

의견 : 잠재적으로 here 문자열은 임시 텍스트 파일을 사용하기 때문에 POSIX 정의에 의한 텍스트 파일 에는 줄 바꿈 문자로 끝나는 줄이 있어야하기 때문에 here-string이 항상 줄 바꿈 개행을 삽입하는 가능한 이유 입니다.

프로세스 대체

tldp.org가 설명 하듯이

프로세스 대체는 프로세스 (또는 프로세스)의 출력을 다른 프로세스의 stdin에 공급합니다.

실제로 이것은 하나의 명령의 stdout 을 다른 명령으로 파이프하는 것과 유사합니다 echo foobar barfoo | wc. 그러나 bash 맨 페이지 에서 으로 표시되어 있음을 알 수 <(list)있습니다. 따라서 기본적으로 여러 (!) 명령의 출력을 리디렉션 할 수 있습니다.

참고 : 기술적 < <으로 한 가지를 언급하는 것이 아니라 <출력의 단일 및 프로세스 리디렉션을 사용 하여 두 가지 리디렉션 을 말합니다 <( . . .).

대체 처리 만하면 어떻게됩니까?

$ echo <(echo bar)
/dev/fd/63

보시다시피, 쉘은 /dev/fd/63출력이 진행되는 임시 파일 디스크립터를 생성합니다 ( Gills의 답변 에 따르면 익명 파이프 임). 즉, <해당 파일 디스크립터를 입력으로 명령에 리디렉션합니다.

따라서 매우 간단한 예는 두 개의 echo 명령 출력을 wc로 프로세스 대체하는 것입니다.

$ wc < <(echo bar;echo foo)
      2       2       8

따라서 여기서는 쉘이 괄호 안에 발생하는 모든 출력에 대한 파일 디스크립터를 작성하고이를 입력으로 경로 재 지정합니다 wc. 예상대로, wc는 두 개의 echo 명령에서 해당 스트림을 수신합니다. 적절하게 우리는 2 단어, 2 줄 및 6 문자와 2 줄 바꿈이 있습니다.

사이드 참고 : 프로세스 대체가로 불릴 수있다 bashism (명령 또는 같은 고급 쉘에서 사용할 수있는 구조 bash지만, POSIX에 의해 지정되지 않음) 있지만 구현되었습니다 ksh이전 배쉬의 존재 KSH man 페이지이 답변이 좋습니다. 같은 쉘 tcshmksh그러나 공정 대체가 없습니다. 그렇다면 프로세스 대체없이 여러 명령의 출력을 다른 명령으로 리디렉션하는 방법은 무엇입니까? 그룹화 및 파이핑!

$ (echo foo;echo bar) | wc
      2       2       8

실제로 이것은 위의 예와 동일하지만 전체 서브 쉘의 stdout을 만들고 wc 파이프와 연결된 stdin을 만들기 때문에 이는 프로세스 대체 와 차이가 있습니다 . 반면에 프로세스 대체는 명령이 임시 파일 디스크립터를 읽도록합니다.

파이핑으로 그룹화 할 수 있다면 왜 프로세스 대체가 필요한가? 때로는 파이프를 사용할 수 없기 때문입니다. 아래의 예를 고려하십시오-두 개의 명령의 출력과 두 diff개의 파일이 필요하며이 경우 두 개의 파일 설명자를 제공합니다.

diff <(ls /bin) <(ls /usr/bin)

7
< <프로세스 대체 에서 stdin을 가져올 때 사용됩니다 . 이러한 명령은 다음과 같습니다 cmd1 < <(cmd2).. 예 :wc < <(date)
John1024


2
< < 그 자체만으로는 문제가되지 않습니다. 프로세스 대체의 경우에는 <그 다음에 나오는 다른 항목이 있습니다.<
immibis

1
@muru 내가 아는 한, <<<Plan 9 rc shell의 유닉스 포트에 의해 처음 구현 된 후 나중에 zsh, bash 및 ksh93에 의해 채택되었습니다. 나는 그것을 bashism이라고 부르지 않을 것이다.
jlliagre

3
배관을 사용할 수없는 경우의 또 다른 예는 : echo 'foo' | read; echo ${REPLY}없는 반환 foo하기 때문에, read- 배관 하위 쉘을 시작하는 서브 쉘에서 시작됩니다. 그러나 하위 쉘이 없기 때문에 read < <(echo 'foo'); echo ${REPLY}올바르게 리턴합니다 foo.
Paddy Landau

26

< < 구문 오류입니다.

$ cat < <
bash: syntax error near unexpected token `<'

< <()프로세스 교체 ( <()(재로 결합 된) <) :

고안된 예 :

$ wc -l < <(grep ntfs /etc/fstab)
4
$ wc -l <(grep ntfs /etc/fstab)
4 /dev/fd/63

프로세스 대체에서는 파일 디스크립터의 경로가 파일 이름처럼 사용됩니다. 파일 이름을 직접 사용하고 싶지 않거나 사용할 수없는 경우 프로세스 대체와 리디렉션을 결합합니다.

명확히하기 위해 < <연산자 가 없습니다 .


나는 당신의 대답으로 <<()보다 <()보다 더 유용하다는 것을 알 수 있습니까?
solfish

1
@solfish <()는 파일 이름과 같은 것을 제공하므로 더 일반적으로 유용합니다- < <()필요하지 않은 stdin을 대체하는 것입니다. 에서 wc, 후자는 더 유용하게 발생합니다. 다른 곳에서는 그다지 유용하지 않을 수도 있습니다
muru

12

< <구문 오류입니다 command1 < <( command2 ). 프로세스 대체가 뒤 따르는 간단한 입력 리디렉션이며 매우 유사하지만 다음과 같은 것은 아닙니다.

command2 | command1

실행중인 가정의 차이는 bash있다 command1가 처음에 현재 쉘에서 실행되는 동안 두 번째 경우에 서브 쉘에서 실행됩니다. 이는 command1프로세스 대체 변형으로 설정된 변수 가 손실되지 않음을 의미합니다 .


11

< <구문 오류가 발생합니다. 올바른 사용법은 다음과 같습니다.

예제의 도움으로 설명 :

< <():

while read line;do
   echo $line
done< <(ls)

위의 예에서 while 루프에 대한 입력은 ls명령 에서 나옵니다. 명령은 한 줄씩 읽고 루프에서 사용할 수 있습니다 echo.

<()프로세스 대체에 사용됩니다. 자세한 정보와 예 <()는이 링크에서 찾을 수 있습니다.

공정 대체 및 파이프

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.