bash
프로세스 대체를 사용하고 프로세스의 출력을 디스크에 저장된 파일로 처리할 수 있습니다 .
$ echo <(ls)
/dev/fd/63
$ ls -lAhF <(ls)
lr-x------ 1 root root 64 Sep 17 12:55 /dev/fd/63 -> pipe:[1652825]
안타깝게도, dash
.
Process Substitution
대시에서 시뮬레이션하는 가장 좋은 방법은 무엇입니까?
/tmp/
출력을 임시 파일( )에 저장한 후 삭제하고 싶지 않습니다 . 다른 방법이 있나요?
답변1
파이프라인을 수동으로 실행하여 셸이 내부적으로 수행하는 작업을 재현할 수 있습니다. 시스템에 항목이 있으면 파일 설명자 섞기를 사용할 수 있습니다. 번역할 수 있습니다./dev/fd/NNN
main_command <(produce_arg1) <(produce_arg2) >(consume_arg3) >(consume_arg4)
도착하다
{ produce_arg1 |
{ produce_arg2 |
{ main_command /dev/fd5 /dev/fd6 /dev/fd3 /dev/fd4 </dev/fd/8 >/dev/fd/9; } 5<&0 3>&1 |
consume_arg3; } 6<&0 4>&1; |
consume_arg4; } 8<&0 9>&1
여러 입력과 출력을 설명하는 좀 더 복잡한 예를 보여 드리겠습니다. 표준 입력에서 읽을 필요가 없고 프로세스 대체를 사용하는 유일한 이유가 명령에 명시적인 파일 이름이 필요하다는 것이라면 간단히 다음을 사용할 수 있습니다 /dev/stdin
.
main_command <(produce_arg1)
produce_arg1 | main_command /dev/stdin
그렇지 않은 경우 사용해야 합니다./dev/fd/NNN
명명된 파이프. 명명된 파이프는 디렉터리 항목이므로 어딘가에 임시 파일을 만들어야 하지만 해당 파일은 이름일 뿐이며 데이터가 포함되어 있지 않습니다.
tmp=$(mktemp -d)
mkfifo "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
produce_arg1 >"$tmp/f1" &
produce_arg2 >"$tmp/f2" &
consume_arg3 <"$tmp/f3" &
consume_arg4 <"$tmp/f4" &
main_command "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
rm -r "$tmp"
답변2
현재 현상금 알림의 문제:
일반적인 예는 너무 복잡합니다. 다음 예제를 구현하는 방법을 설명해 줄 수 있는 사람이 있나요?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)
답이 있을 것 같습니다여기.
그림에서 알 수 있듯이자일스의 대답, 일반적인 아이디어는 "생산자" 명령의 출력을 파이프라인의 여러 단계에서 새 장치 파일1 로 전송하여 파일 이름을 인수로 사용할 수 있는 "소비자" 명령에서 사용할 수 있도록 하는 것입니다(시스템이 액세스를 제공한다고 가정). 파일 설명자에 /dev/fd/X
).
원하는 것을 달성하는 가장 쉬운 방법은 아마도 다음과 같습니다.
xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0
( file1.xz
대신 in을 사용하는 것은 "$1"
가독성을 위한 것이지 단일 명령으로 충분하기 때문 xz -cd
이 아닙니다 .)cat ... | xz -d
첫 번째 "생산자" 명령의 출력은 xz -cd file1.xz
복합 명령( {...}
)으로 파이프되지만 다음 명령의 표준 입력으로 즉시 사용되지는 않습니다.반복됨3
복합 명령 내의 모든 것에 대한 액세스를 허용하는 파일 설명자 /dev/fd/3
. 두 번째 "생산자" 명령의 출력은 xz -cd file2.xz
표준 입력이나 파일 설명자에 있는 어떤 것도 사용하지 않고 표준 입력 및 에서 읽는 3
"소비자" 명령으로 파이프됩니다 .diff
/dev/fd/3
파이프와 파일 설명자 복사본을 추가하여 필요한 만큼 "생산자" 명령에 대한 장치 파일을 제공할 수 있습니다. 예를 들면 다음과 같습니다.
xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0
귀하의 특정 질문과 관련이 없을 수도 있지만 다음 사항에 주목할 가치가 있습니다.
cmd1 <(cmd2) <(cmd3)
, 초기 실행 환경에 다양한 잠재적 영향을 미칩니다cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0
.( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
에서
cmd1 <(cmd2) <(cmd3)
일어나는 일의 반대는 사용자로부터 어떤 입력도 읽을 수 없게 됩니다 . 이렇게 하려면 더 많은 파일 설명자가 필요합니다. 예를 들어 일치시키려면cmd3
cmd1
cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0
diff <(echo foo) <(read var; echo "$var")
당신은 다음과 같은 것이 필요합니다
{ echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0
1이들에 대한 자세한 내용은 U&L에서 확인할 수 있습니다./dev, 하위 디렉터리 및 파일 이해.
답변3
다음 예제를 구현하는 방법을 설명해 줄 수 있는 사람이 있나요?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)
명명된 파이프는 리디렉션보다 이해하기 쉽다고 생각합니다. 따라서 간단히 말하면 다음과 같습니다.
mkfifo p1 p2 # create pipes
cat "$2" | xz -d > p1 & # start the commands in the background
cat "$1" | xz -d > p2 & # with output to the pipes
diff p1 p2 # run 'diff', reading from the pipes
rm p1 p2 # remove them at the end
p1
임시 명명된 파이프 이므로 p2
이름을 무엇이든 지정할 수 있습니다.
/tmp
예를 들어 Gilles의 디렉터리 에 파이프를 만드는 것이 더 현명할 것입니다.답변여기서는 표시할 필요가 없으므로 cat
다음과 같이 하세요.
tmpdir=$(mktemp -d)
mkfifo "$tmpdir/p1" "$tmpdir/p2"
xz -d < "$2" > "$tmpdir/p1" &
xz -d < "$1" > "$tmpdir/p2" &
diff "$tmpdir/p1" "$tmpdir/p2"
rm -r "$tmpdir"
mktemp
( "예쁜" 파일 이름을 만들 수 있으므로 따옴표를 생략할 수도 있습니다 .)
diff
파이프 솔루션에는 주의 사항이 있습니다. 모든 입력을 읽기 전에 주 명령( )이 종료되면 백그라운드 프로세스가 중단될 수 있습니다.
답변4
무엇에 대해:
cat "$2" | xz -d | diff /dev/sdtin /dev/stderr 2<<EOT
`cat "$1" | xz -d`
EOT