Bagaimana cara menyalurkan output dari satu proses ke proses lainnya tetapi hanya mengeksekusi jika yang pertama memiliki output?

23

Bagaimana saya bisa menulis ulang perintah ini hanya untuk email jika ada output dari mailq | grep?

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

Apakah ini mungkin dilakukan dalam satu baris?

Lihat Periksa apakah pipa kosong dan jalankan perintah pada data jika itu bukan untuk kasus yang lebih umum daripada mengirim email.

cosmin
sumber
Sangat mirip: Buat pipa bersyarat pada pengembalian yang tidak kosong (pada Pengguna Super )
G-Man Mengatakan 'Reinstate Monica'

Jawaban:

19

Saya pikir Anda harus menggunakan file temp untuk operasi ini sehingga Anda dapat menggunakan &&operator untuk hanya menjalankan perintah mail jika grep mengembalikan status keluar yang mengatakan itu cocok dengan ini:

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

Jika Anda tidak keberatan file temp menempel di suatu tempat dan dapat menggunakan nama statis untuk itu, Anda bisa melewatkan hal-hal penamaan dan penghapusan khusus:

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

Sunting: Setelah melihat jawaban glenn saya bermain dengan ini lagi dan tampaknya menetapkan variabel menggunakan $()sintaks mengembalikan kode keluar dari perintah, sehingga Anda dapat melewati tes yang digunakannya untuk panjang string dan menggunakannya sebagai gantinya. Ini dia semua dalam satu perintah:

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

Sunting 2: Setelah melihat jawaban Simon, saya memeriksa mailprogram saya . Itu tidak berperilaku seperti yang ia gambarkan secara default, tetapi memang memiliki opsi untuk itu. Dari halaman manual:

-EJika pesan keluar tidak mengandung teks apa pun di bagian pesan pertama atau hanya pesannya, jangan kirimkan tetapi buanglah dengan diam-diam, secara efektif mengatur variabel variabel pada saat startup program. Ini berguna untuk mengirim pesan dari skrip yang dimulai oleh cron (8).

Memungkinkan ini:

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email
Caleb
sumber
1
kekuatan kolaborasi !!
glenn jackman
3
Saya menyarankan jawaban ini bisa dibuat lebih baik dengan menggerakkan solusi terbaik ke atas.
Mark Booth
@ Kartu Memori Suntingan itu tidak perlu, mengingat parameter input mktemptidak akan mengembalikan sesuatu yang perlu dikutip.
Caleb
2
Aku tahu. Anda adalah salah satu dari sedikit orang yang mengerti bahwa kutipan kadang - kadang diperlukan (dan menghilangkannya dengan sengaja). Namun, default harus bisa mengutip kecuali Anda secara eksplisit ingin memanggil glob(split(var)). Anda tidak perlu pemisahan kata atau mengajukan ekspansi glob di sini, jadi jangan tanya mereka. Kami juga harus menunjukkan cara yang benar di situs ini .
Wildcard
@ Kartu Memori Cukup adil. Saya biasanya berlari zshdan saya sebenarnya tidak mendapatkan globbing atau pemisahan kata dalam kasus-kasus seperti ini kecuali saya memintanya, tetapi demi jawaban di sini dan tidak mengetahui lingkungan target yang mengutip dari prinsip itu baik-baik saja.
Caleb
11

Program utilitas ifne ada secara tegas untuk tujuan ini: untuk menjalankan perintah jika input standar tidak kosong.

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

Perintah ifne adalah bagian dari paket moreutils , disebut sebagai "kumpulan alat Unix yang terus berkembang yang tak seorang pun berpikir untuk menulis sejak lama, ketika Unix masih muda."

Guy Hillyer
sumber
8

Anda bisa menyimpan output dalam variabel, dan kemudian memanggil perintah mail jika panjang string tidak nol.

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

Untuk satu baris, gabungkan dua perintah dengan titik koma.

glenn jackman
sumber
1
Alat peraga untuk menggunakan variabel, bukan file temp. Ini membuat saya berpikir tentang ke mana kode keluar berasal dari perintah yang Anda lakukan dengan penugasan variabel, dan tampaknya diteruskan! Lihat jawaban saya yang diperbarui .
Caleb
7

Gunakan maildengan -Eopsi. Di Mac saya, MAIL (1) mengatakan -Ebendera tidak akan mengirim email dengan badan kosong.

-E Jangan mengirim pesan dengan tubuh kosong. Ini berguna untuk kesalahan perpipaan dari skrip cron (8).

Di Mac saya, saya menjalankan tes berikut. Perhatikan bahwa file itu file_does_existmemang ada, tetapi file file_does__not_existitu tidak ada.

Ini mengirim email kepada saya:

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

Ini tidak. Perhatikan bahwa perintah ls file_does_not_exist | egrep ...tidak menghasilkan output apa pun.

$ 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
Stefan Lasiewski
sumber
Caleb mengalahkanmu karenanya.
Gilles 'SANGAT berhenti menjadi jahat'
1
Dia hanya mengalahkan saya dengan 4,75 jam :). Saya melewatkan detail ini dalam jawaban panjangnya.
Stefan Lasiewski
5

Dalam kasus khusus ini, jika Anda mailmendukung -Eopsi , gunakan saja. Dalam kasus umum, Anda dapat mencoba membaca satu karakter; jika ada, mulai perintah postprocessing dan berikan karakter itu dari sisa file.

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

Perhatikan penggunaan yang bermanfaat dari cat. Penambahan dari echo .membuat fungsi ini bekerja bahkan jika karakter pertama dalam input adalah baris baru (ingat bahwa $(…)strip terminal membangun baris baru).

Dengan sebagian besar shell (apa pun selain zsh, sejauh yang saya tahu), jika file dimulai dengan karakter nol, kode ini akan percaya itu kosong. Memperbaiki yang tersisa sebagai latihan untuk pembaca. (Petunjuk: gunakanod di subshell pertama dan printfuntuk mencetak byte pertama.) (Solusi: Cara memeriksa apakah pipa kosong ) Anda mungkin mengalami masalah yang sama jika file dimulai dengan byte yang bukan karakter yang valid pada saat ini lokal; itu lebih mudah diperbaiki dengan menjalankan kode ini LC_ALL=C.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
+1 untuk konyol tapi mungkin berguna dalam skenario lain :) Karena penasaran, mengapa menyuntikkan dan menguji titik alih-alih menguji string kosong? Bukankah itu menimbulkan masalah jika input dimulai dengan titik? Bisakah menggunakan readbantuan menyederhanakan ini?
Caleb
@ Caleb: Ya, saya seharusnya mengatakan saya menjawab pertanyaan dalam judul dan bukan pada situasi tertentu. Lihat hasil edit saya untuk penjelasan tentang titik tersebut. Saya tidak berpikir Anda dapat membedakan baris pertama yang kosong dari file kosong dengan readdi sh portabel (mungkin dimungkinkan dalam bash, ksh atau zsh).
Gilles 'SANGAT berhenti menjadi jahat'
3

IIRC mailperintah BSD dibatalkan jika diberi pesan kosong.

Simon Richter
sumber
1
Program mail pada sistem GNU Linux saya (pusaka mailx 12,4) tidak berperilaku seperti ini secara default, tetapi memiliki sebuah -Epilihan untuk mengaktifkannya .
Caleb
1

Baru-baru ini saya telah belajar tentang nama perintah ifneyang merupakan bagian dari moreutilspaket. Di mana Anda dapat menggunakannya untuk memecahkan masalah khusus ini.

ifne - Jalankan perintah jika input standar tidak kosong

contoh dari halaman manual,

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

Anda bisa menulis ulang perintah Anda menggunakan test -s /dev/stdinuntuk memeriksa apakah ada output dari mailq | grepbagian tersebut.

- 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
trent55
sumber