파이프 라인이 파일 끝을 기다리거나 오류 발생 후 중지하는 방법은 무엇입니까?


12

파이프 shenanigans 에서이 비디오 후 다음 명령을 시도했습니다 .

man -k . | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf | zathura -

기본적으로 사용자가 dmenu에 맨 페이지 목록을 인쇄하여 사용자가 그 중 하나를 선택할 수 있도록 한 다음 xargs를 사용하여 실행합니다 man -Tpdf %(xargs의 입력에서 맨 페이지 git의 pdf를 stdout하기 위해 인쇄) .pdf를 pdf 리더 (zathura)에 전달합니다. ).

문제는 비디오에서 볼 수 있듯이 dmenu에서 하나의 맨 페이지를 선택하기 전에 pdf 리더가 시작된다는 것입니다. 그리고 Esc를 클릭하고 none을 선택하면 PDF 리더가 여전히 열려 문서가 전혀 표시되지 않습니다.

입력이 파일 끝에 도달하거나 입력을받을 때만 PDF 리더 (및 파이프 체인의 다른 명령)가 실행되도록하려면 어떻게해야합니까? 또는 체인 명령 중 하나가 0이 아닌 종료 상태를 반환 한 후 파이프 체인을 중지하려면 어떻게해야합니까 (dmenu가 옵션을 선택하지 않은 오류를 반환하면 다음 명령이 실행되지 않음)?


1
어떤 쉘을 사용하고 있습니까? 이 배쉬인가요?
terdon

bash, zsh 및 sh에서 시도했습니다. 그들 모두는 같은 행동을했습니다.
Seninha

2
예, 행동은 표준 pipefail입니다 .Kusalandanda의 대답에 언급 된 bash 옵션으로 인해 어떤 쉘을 요구했습니다 .
terdon

답변:


12

입력이 파일 끝에 도달하거나 입력을받을 때만 PDF 리더 (및 파이프 체인의 다른 명령)가 실행되도록하려면 어떻게해야합니까?

있습니다 ifne(데비안에서는 moreutils패키지에 있습니다).

ifne 표준 입력이 비어 있지 않은 경우에만 다음 명령을 실행합니다.

귀하의 경우 :

 | ifne zathura -

답변 주셔서 감사합니다, 나는이 명령을 몰랐다! 이 명령 (및의 다른 명령 moreutils)은 원래 유닉스에 있었고 posix에 의해 지정되어 있어야합니다 ... 그것은 기본적이고 유닉스 도구입니다 ...
Seninha

@Seninha의 단순성은 ifne약간 기만적입니다. 유닉스에는 "파이프 피킹 (pipe peek)"작업이 없으므로 ifne종속 명령 실행을 결정하기 전에 실제로 최소 1 바이트를 읽어야합니다. 즉, 테스트 를 수행하고 명령을 실행할 수는 없지만 다른 파이프 를 작성 하고 종속 프로세스를 실행하기 위해 다른 프로세스를 분기하고 전체 스트림을 stdin 파이프에서 다운 스트림 파이프로 복사해야합니다. "빈 입력"사례가 일반적이지 않은 경우 ifne평균적으로 절약하는 것보다 더 많은 리소스를 쉽게 소비 할 수 있습니다.

@ Wumpus.Q. Wumbley 그건 신화 입니다. 파이프에 데이터가 있는지 확인하기 위해 바이트를 읽을 필요가 없습니다 . 여기를 참조 하십시오 . 그리고 Linux에서는 실제로 파이프에서 데이터를 수 있습니다 (즉, 제거하지 않고 데이터를 읽을 수 있음). 나는 여기에 "정식적인"답변에 대한 언급에서 이것과 더 많은 것을 언급했지만 그것들은 아마도 그 사실이 답의 위대함을 방해하는 것처럼 느꼈기 때문에 개조에 의해 제거되었습니다.
mosvy

6

PDF 파일은 검색 가능해야합니다. 모든 PDF 뷰어는 트레일러를 먼저보고 외부 참조 테이블의 오프셋으로 이동해야합니다.

파이프를 찾을 수 없으므로 zathura모든 입력을 임시 파일로 복사 한 다음 일반적으로 해당 임시 파일을 사용하는 난독 한 트릭을 사용합니다. 이런 종류의 "영리한"속임수는 잘못된 희망을 불러 일으켜 사람들이 pdf 파일을 스트리밍 할 수 있다고 가정하도록 유도합니다.

그러나 어쨌든, zathura정말 않는 문서를 표시하기 전에 EOF에 대한 대기, 당신은 hapen에 그것에 대해 아무것도 할 필요가 없습니다 :

(sleep 10; cat file.pdf) | zathura -
# will really show the content of file.pdf after 10 seconds

문제는 zathura파일이 정상이면 창을 열고 옵션이 아닌 경우 오류로 종료하는 옵션이 없다는 것입니다. 모든 것이 정상인 것처럼 그대로 유지됩니다.

$ dd if=file.pdf bs=50000 count=1 status=none | zathura -
error: could not open document  # its window still hanging around showing nothing

$ echo $?
0  # really?

따라서 출력을 임시 파일로 직접 리디렉션하고 zathura모든 것이 정상인 경우 에만 실행 중이더라도 어떤 zathura이유로 든 출력이 마음에 들지 않으면 사용자에게 검은 창이 표시 되지 않을 것이라는 보장은 없습니다. .


Btw,

man -X man

gxditview'70 ;-)에서 똑바로 보이는 경우에도 X11 창에 맨 페이지를 표시합니다.

물론 항상 다음을 사용할 수 있습니다.

... | xargs xterm -e man

다른 많은 개선 사항 외에도 검색 및 적절한 텍스트 선택에 정규식을 사용할 수 있습니다.


6

파이프 라인의 모든 명령은 거의 동시에 시작됩니다. 동기화하는 것은 파이프상의 I / O뿐입니다. 또한 파이프는 파이프 버퍼가 허용하는 한 많은 정보 만 보유 할 수 있습니다.

따라서 파이프 라인의 한 단계 실행을 피할 수 없습니다.

  1. 다른 모든 단계가 시작 되 자마자 해당 단계의 명령이 시작됩니다.
  2. 명령이 파이프를 통해 들어오는 입력을 소비하지 않으면 파이프 라인의 이전 단계를 차단합니다.

대신 파이프 라인을 마치면서 출력을 파일에 씁니다. 그런 다음 해당 파일을 사용하십시오.

예 (하나의 인수를 취하는 함수로서) :

myman () {
    tmpfile=$( mktemp )

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile" && [ -s  "$tmpfile" ]
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}

zathura파이프 라인이 실패 xargs했거나 (0이 아닌 부분이 리턴 된 경우) 생성 된 파일이 비어 있으면 프로그램을 추가로 실행하지 않습니다 .

에서 bash쉘, 당신은 또한 설정할 수 pipefail와 쉘 옵션 set -o pipefail파이프 라인이 실패 파이프 라인에서 첫 번째 명령의 종료 상태를 반환해야하는가. 그리고 당신은 tmpfile변수 를 만들고 싶을 것입니다 local:

myman () {
    local tmpfile=$( mktemp )

    if [ -o pipefail ]; then
        set -o pipefail
        trap 'set +o pipefail' RETURN
    fi

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile"
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}

이것은 설정 pipefail이 아직 설정되지 않은 경우, 함수의 기간에 대한 옵션을 한 다음 필요한 경우 설정을 해제합니다. -s출력 파일 에서 테스트를 제거 합니다.


1
rm -f? 파이프가 tmpfile의 권한을 변경하는 경우를 생각하고 있습니까?
terdon

2
@ terdon 임시 파일이 조기에 제거되는 경우를 생각하고 있습니다. rm -f파일이 이미 제거 된 경우 오류가 발생 zathura하지 않습니다 (아마도 모르겠습니다).
Kusalananda

첫 번째 기능은 예상대로 작동하지 않습니다. 또한 zathura가 검은 색 창을 표시하지만 이제 zathura는 파이프 라인을 따라 실행하지 않고 파이프 라인 완료 후 실행됩니다. 파이프 라인은 xargs의 종료 상태 인 0을 반환하기 때문입니다. 파이프 라인에서 실패한 명령은 dmenu입니다 (아무 것도 선택하지 않으면 1을 반환 함). pipefail옵션 이있는 bash 함수 는 예상대로 작동합니다 (zsh에서도 동일한 옵션이 있음).
Seninha

1
@ Seninha 생성 된 파일이 비어 있지 않은지 여부를 확인하여 첫 번째 기능을 수정했습니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.