Bash / csh: tes untuk akhir file (EOF) dari stdin

2

Saya akan melakukan:

if not eof(stdin):
   pass stdin to program
else:
   do nothing

Saya merasa itu dapat ditulis cukup dekat dengan:

if test ! --is-eof - ; then
  exec program

Masalah yang saya coba selesaikan adalah programmembaca dari stdin tetapi macet jika tidak mendapat input. Saya tidak memiliki akses ke sumber karena programitu programtidak dapat diubah. Input biner lebih besar dari ukuran memori sehingga menempatkan stdin ke file lebih dulu sangat lambat. Memproses semua input line-by-line di bash juga sangat lambat.

Solusinya idealnya bekerja di bawah csh dan bash.

Ole Tange
sumber
2
Anda harus membaca aliran sebelum dapat menguji EOF. Sepertinya Anda memiliki skrip yang dirancang dengan buruk.
fpmurphy
Nah, program apa yang crash? Bukankah lebih baik untuk mencoba dan membuatnya tidak crash?
slhck

Jawaban:

1

Coba baca satu baris dari stdin dulu:

IFS= read -r line
if [[ -n "$line" ]]; then
    # the line is non-empty.
    # add the line back into the stream and pipe it into your program
    { echo "$line"; cat -; } | your_program
fi
glenn jackman
sumber
Jawaban Anda gagal jika baris pertama dari input adalah baris kosong. Saya sarankan if IFS= read -r line; then …. Atau, jika inputnya berupa saluran yang tidak lengkap (mis., echo "The quick brown fox jumps …\c" | OleTange.sh) if IFS= read -r line  ||  [[ -n "$line" ]]; then ….
Scott
Aku suka gagasan itu. Itu memaksakan batas bahwa harus ada \ n sebelum ukuran jumlah memori data, yang suboptimal, tetapi mungkin batas yang dapat diterima. Tampaknya juga tidak berfungsi jika yang pertama \ 0 sebelum yang pertama \ n, yang tidak dapat diterima karena inputnya adalah data biner. Misalnya: printf "abc \ 0def \ nghi \ njkl" | jika ... Bisakah kita meminta readuntuk membaca sejumlah byte (termasuk \ 0) alih-alih satu baris penuh?
Ole Tange
read -N 1tampaknya membantu, tetapi gagal jika karakter pertama adalah \ 0.
Ole Tange
1

Ini tampaknya bekerja di csh dan bash dan menangani dengan baik dengan input biner (juga \ 0 sebagai karakter pertama):

# Set $_FIRST_CHAR_FILE to the name of a temp file.
eval `echo $SHELL | grep -E "/(t)?csh" > /dev/null && echo setenv _FIRST_CHAR_FILE /tmp/$$.first_char_file || echo export _FIRST_CHAR_FILE=/tmp/$$.first_char_file`

dd bs=1 count=1 of=$_FIRST_CHAR_FILE >&/dev/null
test -s "$_FIRST_CHAR_FILE" && ( cat $_FIRST_CHAR_FILE; rm $_FIRST_CHAR_FILE; cat - ) | program

Terima kasih kepada @ glenn-jackman untuk memberikan gagasan membaca sedikit sebelum melewati ini dan sisa stdin cat.

Ole Tange
sumber
0

Masukan apa yang diharapkan oleh program Anda? apakah Anda menyalurkan output dari satu program ke yang lain atau apakah itu membaca file?

Jika Anda menggunakan pengalihan pipa untuk mengumpulkan input ke skrip Anda, maka itu akan melanjutkan eksekusi sampai pasokan input disediakan.

jika Anda mencoba membaca dari suatu file maka gunakan "sementara" atau "sampai" untuk melakukan pekerjaan itu.

Kannan Mohan
sumber
Ini harus menjadi komentar untuk pertanyaan, bukan jawaban
glenn jackman
@glenn: Saya tidak setuju. @ M mengajukan pertanyaan tentang pertanyaan hanya untuk menerangi situasi di mana masing-masing dari dua jawabannya berlaku. ... // ... Saya setuju bahwa itu bukan jawaban yang baik , tetapi itu adalah jawaban.
Scott
0

Saya posting di sini karena ini datang ketika mencari dan karena itu membantu saya debug pada Darwin (snow leopard) pesta di set -x;trap 'test -s /dev/stdin||exit' debuguntuk menemukan panggilan yang mengkonsumsi masukan mewarisi dari script orang tua.

Untuk yang lemah hati:

if [[ -s /dev/fd/0 ]]
    then echo 'Not at EOF'
    else echo 'Currently no input to read'
fi

Uji:

echo $((echo|test -s /dev/stdin)&&! (true|test -s /dev/stdin)&&echo pass||echo fail) ${BASH_VERSINFO[*]}

Tes di atas menghasilkan yang berikut dalam versi dan sistem bash saya.

pass 4 2 45 2 release i386-apple-darwin10.8.0
pass 3 2 48 1 release x86_64-apple-darwin10.0
fail 4 2 37 1 release x86_64-pc-linux-gnu

Menyambungkan ke cat /proc/self/fdinfo/0Debian saya (mengi) tidak memberikan apa pun untuk diuji.

Ceria atau lebih tepatnya cheerEO untuk Kesalahan / Keluaran%)

Vike
sumber
Akan luar biasa jika bekerja secara umum. Tetapi sayangnya tidak: / dev / fd / * tidak ada pada hurd, aix, hpux, qnx, tru64, ultrix. / dev / stdin tidak ada pada irix, aix, hpux, tru64, ultrix.
Ole Tange
0

Jika Anda tidak ingin skrip Anda diblokir dalam upaya mencari sesuatu untuk dibaca, Anda dapat (setidaknya dalam bash) menggunakan pembacaan dengan batas waktu

$ ( read -t 0 var ; echo $? )
1

$ echo foo | ( read -t 0 var ; echo $? )
0

Namun ini tidak menjamin bahwa Anda memiliki EOF tetapi tidak ada yang dapat dibaca saat ini

Hachi
sumber