cmd_drain < <(cmd_src)와 cmd_drain <<< "$(cmd_src)" 사이에 차이점이 있습니까?

cmd_drain < <(cmd_src)와 cmd_drain <<< "$(cmd_src)" 사이에 차이점이 있습니까?

우리 모두 알고 있듯이 이 cmd | read -r var1 var2구성은 파이프로 인해 읽기 명령이 하위 쉘에서 실행되기 때문에 bash에서는 작동하지 않습니다. 나는 이 문제를 해결하곤 했지만 read -r var1 var2 <<< "$(cmd)"최근에 이 구조에 대해 알게 되었고 cmd_drain < <(cmd_src)그것은 잘 작동하는 것 같습니다: read -r var1 var2 < <$(cmd).

이 두 솔루션 사이에 차이점이 있습니까? 아니요~인 것 같다사소한 차이가 있는 경우:

$ hd < <(echo Hello)
00000000  48 65 6c 6c 6f 0a                                 |Hello.|
00000006
$ hd <<< $(echo Hello)
00000000  48 65 6c 6c 6f 0a                                 |Hello.|
00000006

또한 몇 가지 특수 문자를 사용해 보았지만 동일한 결과를 얻었습니다. 내 직관에 따르면 결과는 항상 동일합니다. cmd_drain <<< "$(cmd_src)"먼저 실행 cmd_src하고 전체 결과를 메모리에 버퍼링한 후 에 공급하는 cmd_drain반면 cmd_drain < <(cmd_src)출력은 계속해서 cmd_src에 공급됩니다 cmd_drain. NET 대신 하위 쉘에서 실행된다는 cmd_src | cmd_drain점을 제외하면 이전과 동일하게 작동할 것이라고 가정합니다 . 제 가정이 맞습니까?cmd_srccmd_drain

보너스 질문: 구조체 주변에 참조가 필요합니까 $()?

답변1

예, 귀하의 가정이 정확합니다. cmd_drain < <(cmd_src)(일명 .프로세스 교체, 일반 리디렉션과 결합) Bash는 이를 출력을 읽을 수 <(cmd_src)있는 파일의 경로로 바꿉니다 . cmd_src문서에서:

프로세스 목록은 비동기적으로 실행되며 해당 입력 또는 출력은 파일 이름으로 표시됩니다. 파일 이름은 확장의 결과로 현재 명령에 인수로 전달됩니다. 양식을 사용하는 경우 >(list)파일에 쓰면 목록에 대한 입력이 제공됩니다. 이 형식을 사용 하는 경우 <(list)인수로 전달된 파일을 읽어 목록의 출력을 얻어야 합니다.

에서는 다른 것과 마찬가지로 처리됩니다 cmd_drain <<< "$(cmd_src)". <<< ...여기에 있는 문자열, 그래서:

단어는 물결표 확장, 매개변수 및 변수 확장, 명령 대체, 산술 확장 및 인용 제거를 거칩니다. 경로 이름 확장 및 토큰화가 수행되지 않습니다. 결과는 개행 문자 [...]가 추가된 단일 문자열로 표준 입력의 명령에 제공됩니다.

따라서 거기에 인용할 필요는 없지만 $()특히 여기의 문자열 구문은 <<<토큰화나 파일 이름 확장을 수행하지 않기 때문에 더욱 그렇습니다. 일반적으로 이렇게 해야 합니다.


여기서 문자열 문서의 마지막 문장을 다시 참고하세요. 개행 문자가 추가됩니다.

bash-5.0$ od -c <<< $(printf %s foo)
0000000   f   o   o  \n
0000004
bash-5.0$ od -c < <(printf %s foo)
0000000   f   o   o
0000003

이것이 중요한지 여부는 실행 중인 항목에 따라 다릅니다.

에서 hd <<< $(echo Hello)바꾸기 명령은 출력에서 ​​후행 개행 문자를 제거하고 echo여기서 문자열에는 개행 문자가 추가되어 사실상 동일한 출력을 제공합니다. 그러나 위의 예에서 볼 수 있듯이 줄 바꿈을 제거/추가하는 것은 까다로울 수 있으며 정확히 어떤 cmd_src출력을 얻을 필요는 없습니다 .

관련 정보