วิธีไพพ์เอาต์พุตจากกระบวนการหนึ่งไปยังอีกกระบวนการ แต่จะดำเนินการเฉพาะถ้ากระบวนการแรกมีเอาต์พุตหรือไม่?


23

ฉันสามารถเขียนคำสั่งนี้ไปยังอีเมลเฉพาะในกรณีที่มีการส่งออกจากmailq | grep?

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email

เป็นไปได้ไหมในหนึ่งบรรทัด?

ดูที่ตรวจสอบว่าไพพ์ว่างเปล่าและรันคำสั่งกับข้อมูลหากไม่ได้เป็นตัวพิมพ์ใหญ่กว่าการส่งอีเมล


คำตอบ:


19

ฉันคิดว่าคุณจะต้องใช้ไฟล์ temp สำหรับการดำเนินการนี้เพื่อให้คุณสามารถใช้&&โอเปอเรเตอร์เพื่อเรียกใช้คำสั่ง mail เท่านั้นหาก grep ส่งคืนสถานะการออกที่ระบุว่ามันตรงกับสิ่งนี้:

TMPFILE=`mktemp /tmp/mailqgrep.XXXXXX`; mailq | egrep 'rejected|refused' -A5 -B5 > "$TMPFILE" && mail -s 'dd' email@email < "$TMPFILE"; rm "$TMPFILE"

หากคุณไม่ทราบว่าไฟล์ temp ติดอยู่ที่ใดที่หนึ่งและสามารถใช้ชื่อแบบคงที่ได้คุณสามารถข้ามการตั้งชื่อและการลบแบบพิเศษได้:

 mailq | egrep 'rejected|refused' -A5 -B5 > /tmp/mailqgrep && mail -s 'dd' email@email < /tmp/mailqgrep

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

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) && mail -s 'dd' email@email <<< "$data"

แก้ไข 2:หลังจากเห็นคำตอบของ Simonฉันได้ลองดูmailโปรแกรมของฉัน มันไม่ทำงานในวิธีที่เขาอธิบายโดยค่าเริ่มต้น แต่มีตัวเลือกสำหรับสิ่งนั้น จากหน้าคน:

-Eหากข้อความที่ส่งออกไม่มีข้อความใด ๆ ในส่วนข้อความแรกหรือข้อความเดียวอย่าส่ง แต่ทิ้งไว้เงียบ ๆ ตั้งค่าตัวแปร skipemptybody อย่างมีประสิทธิภาพเมื่อเริ่มต้นโปรแกรม สิ่งนี้มีประโยชน์สำหรับการส่งข้อความจากสคริปต์ที่เริ่มโดย cron (8)

ทำให้เป็นไปได้:

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email

1
พลังของการทำงานร่วมกัน !!
เกล็นแจ็

3
ฉันอยากจะแนะนำคำตอบนี้ได้ดีขึ้นโดยการย้ายทางออกที่ดีที่สุดไปด้านบน
Mark Booth

@Wildcard การแก้ไขนั้นไม่จำเป็นเนื่องจากพารามิเตอร์อินพุตmktempจะไม่ส่งคืนบางสิ่งที่จำเป็นต้องมีการอ้างอิง
Caleb

2
ฉันรู้ว่า. คุณเป็นหนึ่งในไม่กี่คนที่รบกวนจิตใจให้เข้าใจว่าบางครั้งคำพูดมีความจำเป็น (และละเว้นโดยเจตนา) แต่เริ่มต้นควรglob(split(var))จะอ้างเว้นแต่ว่าคุณต้องการที่จะเรียกร้องให้ คุณไม่จำเป็นต้องแยกคำหรือขยายไฟล์ glob ที่นี่ดังนั้นอย่าถามพวกเขา นอกจากนี้เราต้องแสดงวิธีการที่ถูกต้องในเว็บไซต์นี้
สัญลักษณ์แทน

@ Wildcard ยุติธรรมเพียงพอ โดยทั่วไปแล้วฉันจะวิ่งzshและไม่ได้รับความนิยมหรือแยกคำในกรณีเช่นนี้เว้นแต่ฉันจะขอ แต่เพื่อประโยชน์ของคำตอบที่นี่และไม่ทราบว่าสภาพแวดล้อมเป้าหมายที่ออกมาจากหลักการนั้นดี
Caleb

11

โปรแกรมอรรถประโยชน์ifneมีอยู่อย่างชัดเจนเพื่อจุดประสงค์นี้: เพื่อเรียกใช้คำสั่งหากอินพุตมาตรฐานไม่ว่างเปล่า

mailq | egrep 'rejected|refused' -A 5 -B 5 | ifne mail -s 'dd' email@email

คำสั่ง ifne เป็นส่วนหนึ่งของแพ็คเกจmoreutilsซึ่งเรียกว่า "ชุดเครื่องมือ Unix ที่เพิ่มขึ้นซึ่งไม่มีใครคิดที่จะเขียนเมื่อนานมานี้เมื่อ Unix ยังเด็ก"


8

คุณสามารถบันทึกผลลัพธ์ในตัวแปรแล้วเรียกใช้คำสั่ง mail ถ้าความยาวของสตริงไม่เป็นศูนย์

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5)
[[ -n "$data" ]] && mail -s 'dd' email@email <<< "$data"

สำหรับหนึ่งบรรทัดเข้าร่วมสองคำสั่งด้วยเซมิโคลอน


1
อุปกรณ์ประกอบฉากสำหรับการใช้ตัวแปรแทนไฟล์ temp นี่ทำให้ฉันคิดว่ารหัสทางออกไปจากคำสั่งที่คุณทำการกำหนดตัวแปรด้วยและดูเหมือนว่ามันจะถูกส่งต่อไป! ดูของฉันคำตอบการปรับปรุง
Caleb

7

ใช้mailกับ-Eตัวเลือก สำหรับ Mac ของฉัน MAIL (1) ระบุว่าการ-Eตั้งค่าสถานะจะไม่ส่งอีเมลที่มีเนื้อหาว่างเปล่า

-E อย่าส่งข้อความที่มีเนื้อหาว่างเปล่า สิ่งนี้มีประโยชน์สำหรับข้อผิดพลาดการไพพ์จากสคริปต์ cron (8)

ใน Mac ของฉันฉันรันการทดสอบต่อไปนี้ โปรดทราบว่าไฟล์file_does_existนั้นมีอยู่ แต่ไฟล์file_does__not_existนั้นไม่มีอยู่

ส่งอีเมลถึงฉัน:

$ ls file_does_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org

สิ่งนี้ไม่ได้ โปรดทราบว่าคำสั่งls file_does_not_exist | egrep ...ไม่ได้สร้างผลลัพธ์ใด ๆ

$ ls file_does_not_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org
ls: file_does_not_exist: No such file or directory

แม็กเคเล็บเอาชนะคุณไป
Gilles 'หยุดความชั่วร้าย' ใน

1
เขาตีฉันแค่ 4.75 ชั่วโมงเท่านั้น :) ฉันคิดถึงรายละเอียดนี้ในคำตอบที่ยาวของเขา
Stefan Lasiewski

5

ในกรณีนี้หากคุณmailรองรับ-Eตัวเลือกให้ใช้งาน ในกรณีทั่วไปคุณสามารถลองอ่านหนึ่งตัวอักษร หากมีอยู่ให้เริ่มคำสั่ง postprocessing และป้อนอักขระนั้นจากส่วนที่เหลือของไฟล์

pipe_if_not_empty () {
  a=$(dd bs=1 count=1 2>/dev/null; echo .)  # read at most one character
  if [ "$a" != "." ]; then                  # if there were two characters,
    { printf %s "${a%.}";                   # then output the first character
      cat; } |                              # and the rest of the input   
    "$@"                                    # into the specified program
  fi
}

mailq | egrep 'rejected|refused' -A 5 -B 5 |
pipe_if_not_empty mail -s 'dd' email@email

catหมายเหตุการใช้งานของ การเพิ่มecho .ทำให้ฟังก์ชันนี้ทำงานแม้ว่าอักขระตัวแรกในอินพุตจะขึ้นบรรทัดใหม่ (โปรดจำไว้ว่า$(…)โครงสร้างการสร้างตัดบรรทัดใหม่ของเทอร์มินัล)

ด้วย shells ส่วนใหญ่ (สิ่งอื่นนอกเหนือจาก zsh, เท่าที่ฉันรู้), ถ้าไฟล์เริ่มต้นด้วยอักขระ null, โค้ดนี้จะเชื่อว่ามันว่างเปล่า แก้ไขที่เหลือเป็นแบบฝึกหัดสำหรับผู้อ่าน (คำแนะนำ: ใช้odในเชลล์ย่อยแรกและprintfพิมพ์ไบต์แรก) (วิธีแก้ไข: วิธีตรวจสอบว่าไพพ์ว่างเปล่าหรือไม่ ) คุณอาจพบปัญหาเดียวกันหากไฟล์เริ่มต้นด้วยไบต์ที่ไม่ใช่อักขระที่ถูกต้องในปัจจุบัน locale; LC_ALL=Cที่ง่ายต่อการแก้ไขโดยการเรียกใช้รหัสนี้ด้วย


+1 สำหรับไร้สาระ แต่อาจมีประโยชน์ในสถานการณ์อื่น :) จากความอยากรู้เหตุใดจึงฉีดและทดสอบจุดแทนการทดสอบสตริงว่าง นั่นไม่ได้เป็นการแนะนำปัญหาหรือไม่ถ้าอินพุตเริ่มต้นด้วยจุด? การใช้readความช่วยเหลือช่วยทำให้สิ่งนี้ง่ายขึ้นหรือไม่
Caleb

@Caleb: ใช่ฉันควรจะพูดถึงว่าฉันกำลังตอบคำถามในชื่อและไม่ใช่สถานการณ์เฉพาะ ดูการแก้ไขของฉันสำหรับคำอธิบายของจุด ฉันไม่คิดว่าคุณสามารถแยกความแตกต่างบรรทัดแรกว่างจากไฟล์ว่างด้วยreadในแบบพกพา sh (อาจเป็นไปได้ใน bash, ksh หรือ zsh)
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

3

IIRC mailคำสั่งBSD ยกเลิกหากได้รับข้อความว่าง


1
โปรแกรมอีเมลในระบบ GNU ลินุกซ์ของฉัน (Heirloom mailx 12.4) ไม่ประพฤติวิธีนี้โดยเริ่มต้น แต่จะมีตัวเลือกที่จะเปิดใช้งานได้ -E
Caleb

1

เมื่อเร็ว ๆ นี้ฉันได้เรียนรู้เกี่ยวกับชื่อคำสั่งifneซึ่งเป็นส่วนหนึ่งของmoreutilsแพ็คเกจ คุณสามารถใช้เพื่อแก้ไขปัญหานี้ได้ที่ไหน

ifne - รันคำสั่งหากอินพุตมาตรฐานไม่ว่างเปล่า

ตัวอย่างจากหน้าคน

EXAMPLE
       find . -name core | ifne mail -s "Core files found" root

0

คุณสามารถเขียนคำสั่งของคุณอีกครั้งtest -s /dev/stdinเพื่อตรวจสอบว่ามีเอาท์พุทจากmailq | grepส่วนใด

- mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email
+ mailq | egrep 'rejected|refused' -A 5 -B 5 | (test -s /dev/stdin && cat) | mail -s 'dd' email@email
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.