Bir boru hattının dosya sonu için nasıl bekletilmesi veya bir hatadan sonra nasıl durdurulması?


12

Boru maskaralıklarında bu videoyu izledikten sonra aşağıdaki komutu denedim .

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

Temel olarak kullanıcının bunlardan birini seçmesi için dmenu'ya bir sayfa listesi yazdırır, daha sonra çalıştırmak için xargs kullanır man -Tpdf %(xargs girişinden manpage git'in bir pdf'sini yazdırmak için yazdırır) ve pdf'yi bir pdf okuyucuya (zathura'ya iletir) ).

Sorun (videoda gördüğünüz gibi) pdf okuyucu dmenu bir manpage seçmeden önce başlar olmasıdır. Ve Esc'i tıklayıp hiçbirini seçmezsem, pdf okuyucu hala belge göstermeyecek şekilde açıktır.

Pdf okuyucuyu (ve bir boru zincirindeki herhangi bir komutu) yalnızca girdisi bir dosya sonuna ulaştığında veya bir girdi aldığında nasıl çalıştırabilirim? Veya alternatif olarak, zincirleme komutlardan biri sıfırdan farklı bir çıkış durumu döndürdükten sonra nasıl bir boru zinciri durdurabilirim (böylece dmenu bir seçenek seçmemek için bir hata döndürürse, aşağıdaki komutlar çalıştırılmaz)?


1
Hangi kabuğu kullanıyorsun? Bu bash mı?
terdon

Ben bash, zsh ve sh üzerinde denedim. Hepsi aynı davranışa sahipti.
Seninha

2
Evet, davranış standart, pipefailbash'ın Kusalandanda'nın cevabında belirtilen seçeneği nedeniyle hangi mermiyi sordum.
terdon

Yanıtlar:


12

Pdf okuyucuyu (ve bir boru zincirindeki herhangi bir komutu) yalnızca girdisi bir dosya sonuna ulaştığında veya bir girdi aldığında nasıl çalıştırabilirim?

Var ifne(Debian'da moreutilspakette):

ifne yalnızca standart giriş boş değilse aşağıdaki komutu çalıştırır.

Senin durumunda:

 | ifne zathura -

Cevabınız için teşekkürler, bu komutu bilmiyordum! Bu komut (ve diğerleri moreutils) orijinal Unix'te olmalı ve posix tarafından belirtilmiş olmalıdır ... Bu kadar basit ve Unix-ish bir araçtır ...
Seninha

@Seninha Basitliği ifnebiraz aldatıcı. Unix'in "pipe peek" işlemi yoktur, bu nedenle ifnebağımlı komutu çalıştırmaya karar vermeden önce en az bir bayt okumalıdır. Bu, sadece testi yapıp komutu yürütmekle kalmayıp aynı zamanda başka bir boru oluşturması , bağımlı komutu çalıştırmak için başka bir işlemi çatallaması ve tüm akışı stdin borusundan aşağı akış borusuna kopyalaması gerektiği anlamına gelir. "Giriş boş" durumu yaygın değilse ifne, ortalama olarak tasarruf ettiğinden daha fazla kaynağa mal olabilir.

@ Wumpus.Q. Wumbley bu bir efsane - bir boruda veri olup olmadığını belirlemek için herhangi bir bayt okumak zorunda değilsiniz . Buraya bakın . Ve Linux üzerinde aslında olabilir gözetleme bir boru elde edilen veriler (yani kaldırmadan veri okumak). Burada "kanonik" bir cevaba yapılan yorumlar ve daha fazlasından bahsettim, ancak modlar tarafından kaldırıldılar, çünkü muhtemelen bu gerçeklerin cevabın harikalığından uzaklaşmak gibi olduğunu hissettiler.
mosvy

6

Pdf dosyaları aranabilir olması gerekiyordu; herhangi bir pdf görüntüleyici ilk önce treylere bakmak ve oradan xref tablosundan ofsete atlamak zorunda kalacak.

Borular aranamayacağı için, zathuratüm girdiyi geçici bir dosyaya kopyaladığı gizemli bir numara kullanıyor ve daha sonra bu geçici dosyayı genellikle olduğu gibi kullanıyor. Bu tür "zeki" hile yanlış umutlar yaratıyor ve insanları pdf dosyalarının akıcı olduğunu varsaymaya yönlendiriyor.

Ama her durumda, zathuragerçekten yapar belgeyi görüntülemeden önce EOF beklemek, sen Hapen için bunun için bir şey yapmak zorunda değilsiniz:

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

Sorun şu ki zathura, pencereyi yalnızca dosyanın uygun olması durumunda açma seçeneği yok ve bu durumda bir hata ile çıkılıyor - her şey yolunda gibi duruyor:

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

Bu nedenle, çıktıyı geçici bir dosyaya kendiniz yönlendiriyor olsanız ve yalnızca zathuraher şey yolundaysa çalışıyor olsa bile zathura, çıktıyı bir nedenden ötürü beğenmezse kullanıcıya siyah bir pencere ile sunulmayacağının garantisi yoktur. .


btw,

man -X man

gxditview'70 ;-) 'den düz görünse bile, X11 penceresinde bir manpage görüntüleyecektir

Ve elbette, her zaman kullanabilirsiniz:

... | xargs xterm -e man

diğer pek çok geliştirmenin yanı sıra, aramalarda ve uygun metin seçiminde düzenli ifadeler kullanmanıza izin verir.


6

Bir boru hattındaki tüm komutlar hemen hemen aynı anda başlar. Onları senkronize eden sadece boru üzerindeki I / O. Ayrıca, bir boru yalnızca borunun tamponunun izin verdiği kadar bilgi tutabilir.

Bu nedenle bir boru hattının bir aşamasını çalıştırmaktan kaçınamazsınız, çünkü

  1. bu aşamadaki komut, diğer tüm aşamalar zaten başlar başlamaz başlatılır ve
  2. komut, boru üzerinden gelen girişi tüketmezse, boru hattının önceki aşamalarını engeller.

Bunun yerine, boru hattının bitmesine izin verirken çıktıyı bir dosyaya yazın. Sonra bu dosyayı kullanın.

Örnek (bir argüman alan bir işlev olarak):

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

Bu zathura, boru hattı başarısız olursa ( xargssıfır dışında dönen bölüm) veya oluşturulan dosya boşsa , programı çalıştırmaz .

In bashkabuk, ayrıca ayarlamak istediğiniz olabilir pipefailile kabuk seçeneği set -o pipefailboru hattı başarısız boru hattı ilk komutun çıkış durumu dönmek zorunda. Ve tmpfiledeğişkeni yapmak istersiniz 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"
}

Bu pipefail, daha önce ayarlanmamışsa, işlevin süresi seçeneğini ayarlar ve ardından gerekirse ayarını kaldırır. -sÇıkış dosyasındaki testten kurtulur .


1
Neden rm -f? Borunun tmpfile izinlerini değiştirdiği durumları mı düşünüyorsunuz?
terdon

2
@terdon Geçici dosyanın erken kaldırıldığı durumları düşünüyorum. rm -fdosya zaten kaldırılmışsa (muhtemelen zathura, bilmiyorum) hata olmaz.
Kusalananda

İlk işlev beklendiği gibi çalışmaz: Ayrıca zathura'nın siyah bir pencere göstermesini sağlar, ancak şimdi zathura, boru hattının yanında çalışmak yerine boru hattı bitiminden sonra çalışır. Bunun nedeni, boru hattının 0 olan xargs çıkış durumunu döndürmesidir. Boru hattında başarısız olan komut dmenu'dur (hiçbir şey seçmediğimde 1 döndürür). pipefailSeçeneği olan bash işlevi beklendiği gibi çalışır (ve aynı seçeneğe sahip olan zsh'de).
Seninha

1
@Seninha Oluşturulan dosyanın boş olup olmadığını kontrol etmesine izin vererek ilk işlevi düzelttim.
Kusalananda
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.