Làm cách nào để tạo đường ống chờ kết thúc tệp hoặc dừng sau khi xảy ra lỗi?


12

Tôi đã thử các lệnh sau sau khi xem video này trên shenanigans ống.

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

Về cơ bản, nó in một danh sách các trang đến dmenu để người dùng chọn một trong số đó, sau đó nó sử dụng xargs để chạy man -Tpdf %(in ra để xuất bản pdf của manpage git từ đầu vào của xargs) và chuyển pdf sang trình đọc pdf (zathura ).

Vấn đề là (như bạn có thể thấy trong video) trình đọc pdf bắt đầu ngay cả trước khi tôi chọn một trang trong dmenu. Và nếu tôi nhấp vào Esc và không chọn, trình đọc pdf vẫn mở và không hiển thị tài liệu nào cả.

Làm cách nào tôi có thể làm cho trình đọc pdf (và bất kỳ lệnh nào khác trong chuỗi ống) chỉ chạy khi đầu vào của nó đạt đến cuối tệp hoặc khi nào nó nhận được đầu vào? Hoặc, thay vào đó, làm thế nào tôi có thể làm cho một chuỗi ống dừng lại sau khi một trong các lệnh bị xiềng xích trả về trạng thái thoát khác không (để nếu dmenu trả về lỗi vì không chọn tùy chọn, các lệnh sau sẽ không chạy)?


1
Bạn đang sử dụng vỏ gì? Đây có phải là bash không?
terdon

Tôi đã thử nó trên bash, zsh và sh. Tất cả bọn họ đều có hành vi giống nhau.
Seninha

2
Vâng, hành vi là tiêu chuẩn, tôi đã hỏi vỏ nào vì pipefailtùy chọn của bash được đề cập trong câu trả lời của Kusalandanda.
terdon

Câu trả lời:


12

Làm cách nào tôi có thể làm cho trình đọc pdf (và bất kỳ lệnh nào khác trong chuỗi ống) chỉ chạy khi đầu vào của nó đạt đến cuối tệp hoặc khi nào nó nhận được đầu vào?

ifne(trong Debian là trong moreutilsgói):

ifne chạy lệnh sau khi và chỉ khi đầu vào tiêu chuẩn không trống.

Trong trường hợp của bạn:

 | ifne zathura -

Cảm ơn câu trả lời, tôi không biết lệnh này! Lệnh này (và các lệnh khác moreutils) phải có trong Unix gốc và được chỉ định bởi posix ... Đây là một công cụ cơ bản và Unix-ish ...
Seninha

@Seninha Sự đơn giản của ifnemột chút lừa dối. Unix không có hoạt động "ống nhìn trộm", vì vậy ifnethực sự phải đọc ít nhất một byte trước khi quyết định chạy lệnh phụ thuộc. Điều đó có nghĩa là nó không thể thực hiện kiểm tra và thực thi lệnh, mà phải tạo một đường ống khác , rẽ nhánh một quy trình khác để chạy lệnh phụ thuộc và sao chép toàn bộ luồng từ ống stdin sang đường ống hạ lưu. Nếu trường hợp "đầu vào trống" không phổ biến, ifnetrung bình có thể dễ dàng tiêu tốn nhiều tài nguyên hơn mức tiết kiệm.

@ Wumpus.Q.Wumbley đó là một huyền thoại - bạn không phải đọc bất kỳ byte nào để xác định xem có dữ liệu trong một đường ống hay không. Xem ở đây . Và trên Linux, bạn thực sự có thể xem dữ liệu từ một đường ống (tức là đọc dữ liệu mà không xóa dữ liệu đó). Tôi đã đề cập đến vấn đề này và nhiều hơn nữa trong các bình luận cho câu trả lời "kinh điển" ở đây nhưng chúng đã bị xóa bởi các mod vì có lẽ chúng cảm thấy rằng những sự thật đó giống như làm mất đi sự tuyệt vời của câu trả lời.
mosvy

6

Các tệp Pdf được cho là có thể tìm kiếm được; bất kỳ người xem pdf nào cũng sẽ phải nhìn đầu tiên vào đoạn giới thiệu và từ đó nhảy đến phần bù từ bảng xref.

Vì các đường ống không thể tìm kiếm được, nên zathurađang sử dụng một thủ thuật che giấu, trong đó nó sao chép tất cả đầu vào vào một tệp tạm thời, và sau đó sử dụng tệp tạm thời đó như thường lệ. Loại thủ thuật "thông minh" này đang tạo ra những hy vọng sai lầm và khiến mọi người cho rằng các tệp pdf có thể phát được.

Nhưng dù sao, zathurathực sự không chờ đợi cho EOF trước khi hiển thị các tài liệu, bạn không cần phải làm bất cứ điều gì cho đến hapen:

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

Vấn đề là zathurakhông có tùy chọn chỉ mở cửa sổ nếu tệp ổn và thoát với lỗi nếu không phải như vậy - nó sẽ chỉ ở đó như thể mọi thứ đều ổn:

$ 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?

Vì vậy, ngay cả khi bạn tự chuyển hướng đầu ra sang một tệp tạm thời và chỉ chạy zathuranếu mọi thứ đều ổn, không có gì đảm bảo rằng người dùng sẽ không được phục vụ với một cửa sổ đen nếu zathurakhông thích đầu ra vì lý do này hay lý do khác .


Btw

man -X man

sẽ hiển thị trang chủ trong cửa sổ X11 gxditview, ngay cả khi nó nhìn thẳng ra ngoài '70 ;-)

Và, tất nhiên, bạn luôn có thể sử dụng:

... | xargs xterm -e man

trong đó, bên cạnh nhiều cải tiến khác, sẽ cho phép bạn sử dụng các biểu thức thông thường trong các tìm kiếm và lựa chọn văn bản phù hợp.


6

Tất cả các lệnh trong một đường ống bắt đầu khá nhiều cùng một lúc. Chỉ có I / O trên đường ống đồng bộ hóa chúng. Ngoài ra, một đường ống chỉ có thể chứa nhiều thông tin như bộ đệm của đường ống cho phép.

Do đó, bạn không thể tránh chạy một giai đoạn của đường ống, bởi vì

  1. lệnh trong giai đoạn đó được bắt đầu ngay khi tất cả các giai đoạn khác được bắt đầu bằng mọi cách, và
  2. nếu lệnh không tiêu thụ đầu vào đi qua đường ống, nó sẽ chặn các giai đoạn trước của đường ống.

Thay vào đó, hãy viết đầu ra vào một tệp trong khi để đường ống kết thúc. Sau đó sử dụng tập tin đó.

Ví dụ (dưới dạng hàm lấy một đối số):

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"
}

Điều này cũng sẽ không chạy zathurachương trình nếu đường ống bị lỗi ( xargsphần trả về khác không) hoặc tệp được tạo trống.

Trong bashshell, bạn cũng có thể muốn đặt pipefailtùy chọn shell set -o pipefailđể đường ống trả về trạng thái thoát của lệnh đầu tiên trong đường ống bị lỗi. Và bạn sẽ muốn thực hiện tmpfilebiến 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"
}

Điều này đặt pipefailtùy chọn cho thời lượng của chức năng, nếu nó chưa được đặt, sau đó bỏ cài đặt nếu cần. Nó được loại bỏ các -sbài kiểm tra trên tập tin đầu ra.


1
Tại sao rm -f? Bạn có nghĩ về trường hợp đường ống thay đổi quyền của tmpfile không?
terdon

2
@terdon Tôi đang nghĩ đến những trường hợp tập tin tạm thời bị xóa sớm. rm -fsẽ không lỗi nếu tập tin đã bị xóa (có thể bởi zathura, tôi không biết).
Kusalananda

Chức năng đầu tiên không hoạt động như mong đợi: Nó cũng sẽ làm cho zathura hiển thị một cửa sổ màu đen, nhưng bây giờ zathura chạy sau khi kết thúc đường ống, thay vì chạy dọc theo đường ống. Điều này là do đường ống trả về trạng thái thoát của xargs, là 0. Lệnh không thành công trong đường ống là dmenu (trả về 1 khi tôi không chọn gì). Hàm bash với pipefailtùy chọn hoạt động như mong đợi (và trong zsh cũng vậy, có cùng tùy chọn).
Seninha

1
@Seninha Tôi đã sửa chức năng đầu tiên bằng cách để nó kiểm tra xem tệp được tạo có trống không.
Kusalananda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.