สร้างเงื่อนไขไปป์บนการส่งคืนแบบไม่ว่างเปล่า


16

คำตอบ:


9

ifnotemptyฟังก์ชั่นต่อไปนี้ไพพ์อินพุตของคำสั่งที่ส่งเป็นอาร์กิวเมนต์ยกเว้นว่าจะไม่ทำอะไรเลยถ้าอินพุตว่างเปล่า ใช้มันเพื่อท่อsource --fooเข้าไปโดยการเขียนsink --barsource --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
}

หมายเหตุการออกแบบ:

  • ฉันคาดหวังว่าการติดตั้งนี้จะทำงานบนแพลตฟอร์ม POSIX / Unix ทั้งหมด แต่การพูดอย่างเคร่งครัดไม่สอดคล้องกับมาตรฐาน: มันอาศัยddการอ่านมากกว่าหนึ่งไบต์ที่บอกให้อ่านจากอินพุตมาตรฐาน
  • ฉันคิดว่าhead -c 1จะเป็นสิ่งที่เหมาะสมสำหรับการแทนที่dd bs=1 count=1 2>/dev/nullบน Linux
  • ในทางกลับกันhead -n 1จะไม่เหมาะเพราะheadโดยทั่วไปจะบัฟเฟอร์อินพุตและอาจอ่านมากกว่าหนึ่งบรรทัดที่ส่งออก - และเนื่องจากมันอ่านจากไพพ์ไปไบต์พิเศษจึงหายไป
  • read -r headและแม้read -r -n 1 headจะไม่เหมาะสมที่นี่เพราะถ้าอักขระตัวแรกเป็นบรรทัดใหม่headจะถูกตั้งค่าเป็นสตริงว่างทำให้ไม่สามารถแยกความแตกต่างระหว่างอินพุตว่างและอินพุตเริ่มต้นด้วยบรรทัดว่าง
  • เราไม่สามารถเขียนได้head=$(head -c 1)เพราะถ้าอักขระตัวแรกเป็นบรรทัดใหม่การแทนที่คำสั่งจะตัดบรรทัดใหม่สุดท้ายทำให้ไม่สามารถแยกความแตกต่างระหว่างอินพุตว่างและอินพุตที่ขึ้นต้นด้วยบรรทัดว่าง
  • ใน bash, ksh หรือ zsh คุณสามารถแทนที่ได้catด้วย</dev/stdinการเพิ่มประสิทธิภาพของกล้องจุลทรรศน์

pipe_if_not_emptyหากคุณไม่ทราบการจัดเก็บข้อมูลระดับกลางทั้งในหน่วยความจำและนี่คือการดำเนินงานที่ง่ายมากเล็กน้อย

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

นี่คือการใช้งานที่ง่ายขึ้นเล็กน้อยโดยมีข้อแม้ดังนี้

  • ข้อมูลที่ผลิตโดยแหล่งที่มาจะถือว่าว่างถ้าหากมีเพียงตัวอักษรขึ้นบรรทัดใหม่เท่านั้น (อันที่จริงอาจเป็นที่ต้องการ)
  • ข้อมูลที่ป้อนเข้าสู่ sink สิ้นสุดด้วยอักขระขึ้นบรรทัดใหม่หนึ่งตัวไม่ว่าจะมีการขึ้นบรรทัดใหม่จำนวนเท่าใดข้อมูลที่ผลิตโดยแหล่งที่มาลงท้ายด้วย (นี่อาจเป็นปัญหา)

อีกครั้งข้อมูลทั้งหมดจะถูกเก็บไว้ในหน่วยความจำ

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

17

สิ่งนี้น่าจะเหมาะกับคุณ

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

ตัวอย่าง

$ 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

มันง่าย แต่ควรใช้กับคุณ หาก "ฟังก์ชั่น" ของคุณส่งสตริงว่างหรือแม้กระทั่งบรรทัดใหม่ลงไปป์ไลน์ xargs -r จะป้องกันไม่ให้ผ่านไปยัง "ฟังก์ชั่นอื่น"

การอ้างอิงสำหรับ xargs: 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

ฟังก์ชั่นด้านล่างพยายามที่จะอ่านไบต์ที่ 1 และหากประสบความสำเร็จเต็มสะท้อนที่ไบต์และแมวที่เหลือ ควรมีประสิทธิภาพและพกพาได้ 100%

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

กรณีทดสอบ:

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

echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.comฟังก์ชั่นนี้ล้มเหลวสำหรับฉันเมื่อฉันทำงาน มันคิดว่าlineและhereเป็นทั้งผู้รับอีเมลไม่ใช่โทเค็นในเรื่อง ฉันต้องหลบหนีสิ่ง"รอบตัวเพื่อให้มันทำงานได้ อย่างไรก็ตามpipe_if_not_emptyฟังก์ชั่นจากคำตอบที่ได้รับการยอมรับนั้นใช้ได้ผลสำหรับฉันแม้จะไม่หนีอะไร
kuzzooroo

2

อย่างน้อยสิ่งที่ชอบงานนี้:

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

โปรดทราบว่าข้างต้นจะพิจารณาฟีดบรรทัดและอักขระพิเศษอื่น ๆ เป็นเอาท์พุทดังนั้นบรรทัดว่างที่ส่งผ่านไปยังหากคำสั่งจะถูกพิจารณาว่าเป็นเอาต์พุต เพียงเพิ่มขีด จำกัด -gt หากโดยปกติเอาต์พุตของคุณควรสูงกว่า 1 ไบต์ :)


yourothercommandyourcommandไม่เคยเห็นการส่งออกของ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

2

แทนsender | receiver:

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

หรือคุณสามารถทำให้วัตถุประสงค์ทั่วไปมากขึ้นโดยการเปลี่ยนเพื่อรับโปรแกรมการรับเป็นอาร์กิวเมนต์ในคำตอบของ Gilles:

tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | "$@"; fi; }
sender | tester receiver
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.