파이프가 파일의 끝을 기다리거나 오류 후에 중지되도록 하려면 어떻게 해야 합니까?

파이프가 파일의 끝을 기다리거나 오류 후에 중지되도록 하려면 어떻게 해야 합니까?

시청 후 다음 명령을 시도했습니다.이 비디오배관 장난에 대해서.

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

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

문제는 (비디오에서 볼 수 있듯이) dmenu에서 맨페이지를 선택하기 전에도 PDF 리더가 시작된다는 것입니다. Esc를 클릭하고 없음을 선택하면 PDF 리더가 열린 상태로 유지되고 문서가 전혀 표시되지 않습니다.

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

답변1

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

가지다ifnemoreutils(데비안에서는 패키지에 있습니다 ):

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

귀하의 경우:

… | ifne zathura -

답변2

PDF 파일은 검색 가능해야 합니다. 모든 PDF 뷰어는 먼저 예고편을 본 다음 거기에서 외부 참조 테이블의 오프셋으로 이동해야 합니다.

파이프를 검색할 수 없기 때문에 zathura모든 입력을 임시 파일에 복사한 다음 해당 임시 파일을 정상적으로 사용하는 난독화 트릭이 사용됩니다. 이 "영리한" 속임수는 잘못된 희망을 조성하고 사람들이 PDF 파일을 스트리밍할 수 있다고 믿게 만듭니다.

그런데 어쨌든 zathura정말하다문서를 표시하기 전에 EOF를 기다리십시오. 이를 위해 아무것도 할 필요가 없습니다.

(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


그런데,

man -X man

gxditview비록 70년대에서 나온 것처럼 보이지만 X11 창에 맨페이지를 표시합니다 ;-)

물론, 언제든지 다음을 사용할 수 있습니다.

... | xargs xterm -e man

기타 많은 향상된 기능 외에도 검색 및 올바른 텍스트 선택에 정규식을 사용할 수 있습니다.

답변3

파이프라인의 모든 명령은 거의 동시에 시작됩니다. 파이프의 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만들고 싶을 것입니다 .tmpfilelocal

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출력 파일에 대한 테스트를 제거합니다 .

관련 정보