Saya memiliki program yang menghasilkan informasi bermanfaat stdout
tetapi juga membaca dari stdin
. Saya ingin mengarahkan output standarnya ke file tanpa memberikan apa pun pada input standar. Sejauh ini, sangat bagus: Saya bisa melakukan:
program > output
dan jangan melakukan apa pun di tty.
Namun, masalahnya adalah saya ingin melakukan ini di latar belakang. Jika aku melakukan:
program > output &
program akan ditangguhkan ("ditangguhkan (tty input)").
Jika aku melakukan:
program < /dev/null > output &
program berakhir segera karena mencapai EOF.
Tampaknya apa yang saya butuhkan adalah menyalurkan ke program
sesuatu yang tidak melakukan apa pun untuk waktu yang tidak terbatas dan tidak membaca stdin
. Pendekatan berikut bekerja:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
Namun, ini semua sangat jelek. Ada memiliki menjadi cara yang elegan, menggunakan standar utilitas Unix, untuk "melakukan apa-apa, tanpa batas" (untuk parafrase man true
). Bagaimana saya bisa mencapai ini? (Kriteria utama saya untuk keanggunan di sini: tidak ada file sementara; tidak ada sibuk menunggu atau bangun berkala; tidak ada utilitas eksotis; sesingkat mungkin.)
su -c 'program | output &' user
. Saya akan mengajukan pertanyaan serupa dengan menciptakan pekerjaan latar belakang sebagai metode yang dapat diterima untuk menangani "layanan / daemon." Saya juga memperhatikan bahwa saya tidak bisa mengarahkan ulangSTDERR
tanpa juga mengarahkan ulangSTDOUT
. Solusi tempat programA mengirimSTDOUT
keSTDIN
programB, lalu mengalihkanSTDERR
ke file log:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -c 'while true; do true; done | cat > ~/output &' user
?1<&-
itu akan keluar dari program Anda?Jawaban:
Dalam shell yang mendukungnya (ksh, zsh, bash4), Anda bisa mulai
program
sebagai proses bersama .ksh
:program > output |&
zsh
,bash
:coproc program > output
Itu dimulai
program
di latar belakang dengan inputnya dialihkan dari apipe
. Ujung pipa lainnya terbuka ke shell.Tiga manfaat dari pendekatan itu
program
mati (gunakanwait
untuk menunggu)program
akan berakhir (dapatkaneof
stdin-nya jika shell keluar).sumber
tail -f /dev/null
tidak ideal karena membaca setiap detik aktif/dev/null
(versi terbaru dari GNU tail di Linux menggunakan inotify sebenarnya ada bug ).sleep inf
atau yang lebih portabel setarasleep 2147483647
adalah pendekatan yang lebih baik untuk perintah yang duduk di sana tidak melakukan IMO (catatan yangsleep
dibangun dalam beberapa shell sepertiksh93
ataumksh
).Saya tidak berpikir Anda akan mendapatkan yang lebih elegan dari pada
Anda sudah menyarankan (dengan asumsi ini menggunakan inotify internal, seharusnya tidak ada polling atau bangun, jadi selain terlihat aneh, itu harus cukup).
Anda memerlukan utilitas yang akan berjalan tanpa batas waktu, akan tetap membuka stdout, tetapi tidak akan benar-benar menulis apa pun untuk stdout, dan tidak akan keluar ketika stdin ditutup. Sesuatu seperti
yes
menulis di stdout.cat
akan keluar ketika stdinnya ditutup (atau apa pun yang Anda arahkan kembali ke dalamnya sudah selesai). Saya pikirsleep 1000000000d
mungkin berhasil, tetapitail
jelas lebih baik. Kotak Debian saya memilikitailf
perintah yang mempersingkat sedikit.Mengambil taktik berbeda, bagaimana menjalankan program di bawah
screen
?sumber
tail -f /dev/null
pendekatan yang terbaik dan merasa cukup elegan juga, karena penggunaan perintah cocok dengan tujuan yang dimaksud dengan sangat dekat.strace tail -f /dev/null
tampaknya yangtail
menggunakaninotify
dan bahwa bangun terjadi dalam kasus konyol sepertisudo touch /dev/null
. Sangat menyedihkan bahwa tampaknya tidak ada solusi yang lebih baik ... Saya ingin tahu yang mana syscall yang tepat untuk digunakan untuk mengimplementasikan solusi yang lebih baik.pause
, tetapi tidak terpapar langsung ke antarmuka shell.screen
, tapi ini untuk menjalankan beberapa kejadian program dari skrip shell untuk tujuan pengujian, jadi menggunakanscreen
sedikit berlebihan.sleep infinity
adalah solusi paling jelas yang saya tahu.Anda dapat menggunakan
infinity
karenasleep
menerima angka floating point * , yang dapat berupa desimal , heksadesimal , tak terhingga , atau NaN , menurutman strtod
.* Ini bukan bagian dari standar POSIX, jadi tidak portabel seperti
tail -f /dev/null
. Namun, itu didukung dalam GNU coreutils (Linux) dan BSD (digunakan pada Mac) (tampaknya tidak didukung pada versi Mac yang lebih baru - lihat komentar).sumber
sleep infinity
juga berfungsi pada BSD dan Mac .sleep infinity
menunggu maksimal 24 hari; siapa yang benarsleep
utilitas tidak terbatas pada 24 hari ; itu hanya syscall pertama yang tidur selama 24 hari, dan setelah itu akan melakukan lebih banyak syscalls tersebut. Lihat komentar saya di sini: stackoverflow.com/questions/2935183/…Ya,
2^31-1
adalah angka yang terbatas, dan itu tidak akan berjalan selamanya , tapi saya akan memberi Anda $ 1000 ketika tidur akhirnya habis. (Petunjuk: salah satu dari kita akan mati saat itu.)sumber
sleep 2147483647d
...Anda dapat membuat biner yang melakukan hal itu dengan:
sumber
Berikut saran lain menggunakan utilitas Unix standar, untuk "tidak melakukan apa-apa, tanpa batas" .
Ini akan mengaktifkan sebuah shell yang segera dikirim
SIGSTOP
, yang menunda proses. Ini digunakan sebagai "input" untuk program Anda. KelengkapannyaSIGSTOP
adalahSIGCONT
, yaitu jika Anda tahu shell memiliki PID 12345 Anda dapatkill -CONT 12345
membuatnya terus.sumber
Di Linux, Anda dapat melakukan:
Di Linux, membuka / dev / fd / x di mana x adalah deskriptor file ke ujung penulisan pipa, membuat Anda ujung pembacaan pipa, jadi di sini sama seperti pada stdin program. Jadi pada dasarnya,
read
tidak akan pernah kembali, karena satu-satunya hal yang dapat menulis ke pipa itu sendiri, danread
tidak menghasilkan apa pun.Ini juga akan bekerja pada FreeBSD atau Solaris, tetapi untuk alasan lain. Di sana, membuka / dev / fd / 1 memberi Anda sumber daya yang sama dengan buka pada fd 1 seperti yang Anda harapkan dan seperti kebanyakan sistem kecuali Linux, jadi akhir penulisan pipa. Namun, pada FreeBSD dan Solaris, pipa dua arah. Jadi selama
program
tidak menulis ke stdin-nya (tidak ada aplikasi tidak), tidakread
akan mendapatkan apa pun untuk membaca dari arah pipa.Pada sistem di mana pipa tidak dua arah,
read
mungkin akan gagal dengan kesalahan ketika mencoba membaca dari deskriptor file tulis saja. Perhatikan juga bahwa tidak semua sistem memiliki/dev/fd/x
.sumber
x
dengan bash; lebih jauh dengan zsh Anda hanya dapat melakukannyaread
dan berfungsi (meskipun saya tidak mengerti mengapa!). Apakah trik ini khusus untuk Linux, atau apakah ini berfungsi pada semua sistem * nix?read
sendiri, itu akan membaca dari stdin. Jadi jika terminal, itu akan membaca apa yang Anda ketik sampai Anda menekan enter.read
dan berhasil ?read | program > output
dan bekerja dengan cara yang sama seperti yang Anda sarankan. (Dan saya tidak mengerti mengapa.)Stéphane Chazelas'
read
solusi bekerja pada Mac OS X serta jika fd membaca akan dibuka pada/dev/fd/1
.Untuk dapat membunuh
tail -f /dev/null
dalam skrip (dengan SIGINT, misalnya) perlu untuk latar belakangtail
perintah danwait
.sumber
Redirect
/dev/zero
sebagai input standar!sumber