대시에서 프로세스 대체를 에뮬레이트하는 방법?


18

에서 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/가 삭제해야합니다 ( ). 다른 방법이 있습니까?


당신이하려는 일에 따라 파이프를 사용할 수 있습니다.
Eric Renouf

솔직히, 이식성이 주요 관심사가 아니라면 bash장치에 설치하는 것이 쉽지 않을까요?
Arkadiusz Drabczyk

1
현상금 통지에 제공 한 예는 이 링크 된 답변 의 주제입니다 . 표시된 바와 같이, Gilles의 답변의 단순화 된 버전 ( 대신에 가용성을 /dev/fd사용하고 사용 한다고 가정 )은 다음과 같습니다 . xz -cd <file>cat <file> | xz -dxz -cd "$1" | { xz -cd "$2" | { diff /dev/fd/3 /dev/fd/4; } 3<&0; } 4<&0
fra-san

1
@ fra-san-그것이 실제로 필요한 것입니다. 원하는 경우 답변을 만들 수 있습니다. 감사.
Martin Vegter

답변:


4

현재 현상금 통지의 질문 :

일반적인 예는 너무 복잡합니다. 누군가 다음 예제를 구현하는 방법을 설명해 주시겠습니까?diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

여기 에 대답이있는 것 같습니다 .

Gilles의 답변 에서 볼 수 있듯이 일반적인 아이디어는 "프로듀서"명령의 출력을 파이프 라인의 여러 단계에서 새 장치 파일 1 로 보내서 "소비자"명령에 사용할 수있게하는 것입니다. 파일 이름은 인수로 사용할 수 있습니다. 시스템에서 파일 디스크립터에 대한 액세스 권한을)으로 가정합니다 /dev/fd/X.

찾고있는 것을 달성하는 가장 간단한 방법은 다음과 같습니다.

xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0

(사용 file1.xz대신에 "$1"가독성과 xz -cd대신에 cat ... | xz -d하나의 명령이 충분히 있기 때문에).

첫 번째 "생산자"명령의 출력은 xz -cd file1.xz복합 명령 ( {...})으로 파이프됩니다 . 그러나 다음 명령의 표준 입력으로 즉시 소비되는 대신 파일 디스크립터에 복제 되어 3복합 명령 내의 모든 항목에 액세스 할 수 있습니다 /dev/fd/3. xz -cd file2.xz표준 입력이나 파일 디스크립터에서 아무것도 사용하지 않는 두 번째 "producer"명령의 출력은 3"consumer"명령으로 파이프되어 diff표준 입력과에서 읽습니다 /dev/fd/3.

필요한만큼 많은 "프로듀서"명령에 대한 장치 파일을 제공하기 위해 파이핑 및 파일 디스크립터 복제를 추가 할 수 있습니다. 예 :

xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0

특정 질문과 관련이 없을 수도 있지만 다음 사항에 유의하십시오.

  1. 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 )초기 실행 환경에 다른 잠재적 인 효과가있다.

  2. 에서 일어나는 것과는 달리 cmd1 <(cmd2) <(cmd3), cmd3cmd1에서는 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 및 해당 하위 디렉토리 및 파일 이해) .


12

배관을 수동으로 수행하여 후드에서 쉘이 수행하는 작업을 재현 할 수 있습니다. 시스템에 항목이있는 경우 파일 디스크립터 셔플 링을 사용할 수 있습니다./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
</dev/fd/8 >/dev/fd/9<&8 >&9Linux와 동일하지 않으므로 피해야합니다.
Stéphane Chazelas

@Gilles-복잡한 예제로 인해 혼란 스럽습니다. 에뮬레이션하는 방법을 보여 주 diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)시겠습니까?
Martin Vegter

3

누군가 다음 예제를 구현하는 방법을 설명해 주시겠습니까?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

명명 된 파이프는 리디렉션보다 grok하기가 더 간단하다고 생각합니다.

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모든 입력을 읽기 전에 주 명령 ( )이 죽으면 백그라운드 프로세스가 중단 될 수 있다는 경고가 있습니다.


0

는 어때:

cat "$2" | xz -d | diff /dev/sdtin /dev/stderr 2<<EOT
`cat "$1" | xz -d`
EOT
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.