menekan pesan stderr dalam skrip bash

49

Pertimbangkan nama skrip berikut (agak konyol) 'test1.sh':

#/bin/bash
#
sleep 10 &
echo sleep pid = $!
pkill sleep

Ketika saya menjalankannya, saya tidak hanya mendapatkan output dari gema, tetapi laporan bash tentang kematian tidur di stderr:

$ ./test1.sh
sleep pid = 3551
./test1.sh: line 5:  3551 Terminated              sleep 10

Dalam hal ini, saya ingin menekan hasil cetak ke stderr. Saya tahu saya bisa melakukannya di baris perintah, seperti pada:

$ ./test1.sh 2> /dev/null

... tetapi apakah ada cara untuk menekannya dari dalam skrip? (Saya tahu saya bisa membungkusnya dalam skrip kedua dan meminta pembungkusnya mengalihkannya, tetapi pasti ada sesuatu yang lebih mudah ...)

fearless_fool
sumber
apakah Anda mencoba menambahkan pengalihan 2> / dev / null setelah tidur pkill?
rahul
@ Rahul: ya saya lakukan - pkill tidak menghasilkan pesan, bash
fearless_fool
Saya menggunakan kill bukan pkill dan tidak mendapatkan stderr. aneh ..
rahul
@rahul: mungkinkah itu built in vs non-built in thing? Apakah Anda mencobanya dengan pkill juga?
fearless_fool
ya, saya percaya itu. Saya mendapatkan kesalahan yang sama dengan pkill, tetapi tidak dengan kill. Saat menggunakan kill, saya menggunakan pid bukan nama proc.
rahul

Jawaban:

73

Kamu benar; pkill tidak menghasilkan pesan, tapi bash. Anda menyarankan itu

$ ./test1.sh 2> /dev/null

adalah solusi yang memungkinkan. Seperti yang ditunjukkan UVV, tindakan setara dari dalam skrip adalah

exec 2> /dev/null

Ini mengarahkan ulang stderr untuk skrip /dev/null dari pernyataan ini hingga diubah kembali. Cara kikuk untuk mengubahnya kembali meliputi

exec 2> /dev/tty

yang mengarahkan stderr ke terminal. Ini mungkin (tetapi tidak harus) di tempat asalnya.

Atau

exec 2>&1

yang menetapkan stderr sama dengan stdout, dan kemungkinan besar salah.

Cara yang lebih andal adalah

exec 3> & 2
exec 2> / dev / null
(melakukan hal-hal di mana Anda tidak ingin melihat stderr.) 
exec 2> & 3

yang menyimpan stderr asli dalam file descriptor 3, dan kemudian mengembalikannya.

Cara lain untuk menekan hanya pengumuman proses kematian termasuk

(sleep 10 & pkill sleep) 2> /dev/null

dan

{ sleep 10 & pkill sleep;} 2> /dev/null

yang mengubah stderr hanya untuk perintah yang dikelompokkan.

Scott
sumber
Ini adalah jawaban yang sangat bagus dan terperinci. Terima kasih Pak!
Keenan Lawrence
Apakah ada bahaya yang terkait dengan penyimpanan stdindan stderrdeskriptor file baru, mengirim deskriptor asli ke /dev/nulldan kemudian mengembalikannya?
Alexej Magura
Yah, saya kira itu, jika Anda menjalankan sebuah program yang (tanpa sepengetahuan Anda) menulis ke file deskriptor 3 (atau 4), operasi itu akan gagal dalam keadaan normal. Tetapi program dapat ditulis untuk mengabaikan kegagalan dan melanjutkan tanpa melaporkannya; maka Anda tidak akan pernah tahu. Tetapi jika file deskriptor 1 (atau 2) Anda "diparkir" pada file deskriptor 3 (atau 4), maka program itu tiba-tiba akan menulis ke stdout atau stderr skrip Anda. Tapi itu contoh yang sangat dibuat-buat, dan masih minim bahaya. Apakah Anda memiliki sesuatu dalam pikiran?
Scott
1
FWIW, saya mendukung pendekatan perintah yang dikelompokkan Scott, yaitu{ sleep 10 & pkill sleep;} 2> /dev/null
fearless_fool
9

Menurut ini, Anda dapat melakukan sesuatu seperti berikut:

#!/bin/bash
exec 2>/dev/null
ls -al test
UVV
sumber