우리 모두 알고 있듯이 이 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_src
cmd_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
출력을 얻을 필요는 없습니다 .