Boruyu boş olmayan dönüşlerde koşullu hale getirme


Yanıtlar:


9

Aşağıdaki ifnotemptyişlev, girdiyi bağımsız değişken olarak iletilen komuta bağlar, ancak giriş boşsa hiçbir şey yapmaz. Boru için kullanın source --fooiçine sink --baryazı ile source --foo | pipe_if_not_empty sink --bar.

pipe_if_not_empty () {
  head=$(dd bs=1 count=1 2>/dev/null; echo a)
  head=${head%a}
  if [ "x$head" != x"" ]; then
    { printf %s "$head"; cat; } | "$@"
  fi
}

Tasarım notları:

  • Bu uygulamanın tüm POSIX / Unix platformlarında çalışmasını beklerim, ancak kesinlikle standartlarla uyumlu değildir: ddstandart girdisinde okuması söylenen bir bayttan daha fazla okumaya dayanmaz.
  • Linux head -c 1için uygun bir yedek olacağını düşünüyorum dd bs=1 count=1 2>/dev/null.
  • Öte yandan, genellikle girdisini tamponladığı ve çıkardığı bir satırdan daha fazlasını okuyabileceği head -n 1için uygun olmaz head- ve bir borudan okuduğundan, ekstra baytlar kaybolur.
  • read -r headve hatta read -r -n 1 headburada bile uygun değildir, çünkü ilk karakter yeni bir satırsa, headboş dizeye ayarlanır ve boş giriş ile boş bir satırdan başlayarak girdi arasında ayrım yapılmasını imkansız hale getirir.
  • Sadece yazamayız head=$(head -c 1)çünkü ilk karakter yeni satırsa, komut ikamesi son satırsonu çizgisini kaldırarak boş satır ile boş satırdan başlayarak girdi arasında ayrım yapmayı imkansız hale getirir.
  • Bash, ksh veya zsh, değiştirmek olabilir cattarafından </dev/stdinmikroskobik bir performans kazancı için.

Tüm ara verileri hafızada saklamak sakıncası yoksa, işte çok daha basit bir uygulama pipe_if_not_empty.

pipe_if_not_empty () {
  input=$(cat; echo a);
  if [ "x$input" != x"a" ]; then
    { printf %s "${input%a}"; } | "$@"
  fi
}

İşte aşağıdaki uyarılarla biraz daha basit bir uygulama:

  • Kaynak tarafından üretilen veriler yalnızca ve yalnızca satırsonu karakterlerden oluşuyorsa boş kabul edilir. (Bu aslında istenebilir.)
  • Lavaboya beslenen veriler, kaynak tarafından üretilen verinin kaç satırsonu olursa olsun, tam bir satırsonu karakteriyle biter. (Bu bir sorun olabilir.)

Yine, tüm veriler bellekte saklanır.

pipe_if_not_empty () {
  input=$(cat);
  if [ "x$input" != x"" ]; then
    { printf '%s\n' "${input}"; } | "$@"
  fi
}

17

Bu senin için çalışmalı

$ --a function-- | [ xargs -r ] --another function--

Bir örnek

$ echo -e "\n\n" | xargs -r ls
$ # No output. ls did not run.
$ echo -e "\n\n1" | xargs -r ls
ls: cannot access 1: No such file or directory

Çok basit ama sizin için işe yaramalı. Eğer "bir işlev" iniz boş bir dize veya hatta yeni bir satır gönderirse, xargs -r "başka bir işleve" geçişi önler.

Xargs için referans: http://www.oreillynet.com/linux/cmd/cmd.csp?path=x/xargs

-r, --no-run-if-empty
Do not run command if standard input contains only blanks.


4

Aşağıdaki işlev 1. baytı okumaya çalışır ve eğer başarılı olursa o bayt ve geri kalanını kediler. Verimli ve% 100 taşınabilir olmalıdır.

if_read() {
    IFS="" read -rN 1 BYTE && { echo -nE "$BYTE"; cat; } | "$@";
}

Test senaryoları:

$ echo -n | if_read wc -c
$ echo | if_read wc -c
1
$ echo -en "\nX" | if_read wc -c
2
$

Çalıştığımda bu işlev benim için başarısız oluyor echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.com. Konudaki belirteçleri değil, e-postanın alıcıları olduğunu lineve hereher ikisinin de alıcı olduğunu düşünür . "İşe başlamak için çevreden kaçmak zorundayım . Ancak, pipe_if_not_emptykabul edilen cevabın işlevi hiçbir şeyden kaçmadan bile benim için çalışıyor.
kuzzooroo

2

En azından böyle bir şey işe yarıyor:

yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi

Lütfen yukarıdakilerin satır beslemelerini ve diğer özel karakterleri çıktı olarak kabul edeceğini unutmayın, bu nedenle ifade bir çıktı olarak kabul edilecekse boş bir satır geçti. Çıktınız genellikle 1 bayttan yüksekse -gt sınırını yükseltin :)


yourothercommandçıkışını asla görmez yourcommand.
sonraki duyuruya kadar duraklatıldı.

2

Yerine sender | receiver:

tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | receiver; fi; }
sender | tester

Veya alma programını Gilles'in cevabındaki gibi bir argüman olarak kabul etmesini değiştirerek daha genel bir amaç haline getirebilirsiniz:

tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | "$@"; fi; }
sender | tester receiver
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.