OS X, bash: kurang bekerja pada deskriptor file terbuka, cat tidak

10

Dalam skrip bash yang sedang saya kerjakan (yang harus berjalan di Ubuntu dan OS X), saya perlu mengarahkan output dari ratusan perintah ke file.
Daripada menambahkan &>...semuanya, saya hanya melakukannya

exec 9>&1
exec 5<>/tmp/some-file.txt
exec 1>&5

Sejauh ini bagus, tetapi di tengah-tengah semua perintah itu, saya perlu membaca semua yang telah ditulis sejauh ini, sambil menjaga file deskriptor tetap terbuka.
Sekarang, di Ubuntu saya cukup melakukannya

cat /dev/fd/5

atau

tee </dev/fd/5

tetapi pada OS X, tidak ada yang dicetak sama sekali (dan perintah segera keluar).
Namun, menggunakan lesssaya bisa melihat isi file di keduanya.
Saya dapat mencapai efek di atas (bekerja pada kedua OS'es) dengan menggunakan

less /dev/fd/5 | tee

tapi itu seperti retasan.

Jadi, mengapa lesstampaknya bisa melihat hal-hal yang cattidak bisa di OS X? (Atau apakah semua keturunan BSD terpengaruh?)
Atau apakah saya melakukan sesuatu yang salah?

Siguza
sumber

Jawaban:

13

Pada OS X, seperti pada semua sistem di mana mereka didukung kecuali Linux , pembukaan /dev/fd/xadalah seperti melakukan a dup(x), fd yang dihasilkan lebih atau kurang menunjuk ke deskripsi file terbuka yang sama seperti pada fd x dan khususnya akan memiliki offset yang sama dalam file.

Linux adalah pengecualian di sini. Di Linux, /dev/fd/xadalah symlink ke /proc/self/fd/xdan /proc/self/fd/xmerupakan pseudo-symlink ke file yang terbuka di fd x. Di Linux saat Anda melakukan open("/dev/fd/x", somemode), Anda mendapatkan deskripsi file terbuka baru ke file yang sama seperti buka x. Fd baru yang Anda peroleh tidak terkait dengan fd x dengan cara apa pun. Secara khusus, offset akan berada di awal file (kecuali jika Anda membukanya O_APPENDtentu saja) dan mode (baca / tulis / tambahkan ...) dapat berbeda dari yang ada di fd x (Anda bahkan bisa mendapatkan sesuatu yang sangat berbeda dari apa yang ada di fd x, seperti ujung pipa saat membukanya dalam mode yang berlawanan). (Itu juga berarti bahwa itu tidak berfungsi untuk soket misalnya yang Anda tidak dapat membuka () ).

Jadi, di Linux, ketika Anda melakukannya

exec 5<> file
echo test >&5

Offset fd 5 ada di akhir file. Jika kamu melakukan

cat <&5

Anda tidak mendapat apa-apa.

Masih ketika Anda melakukannya:

cat /dev/fd/5

Anda lihat testkarena catmendapat read-only fd baru untuk filetidak terkait dengan fd 5.

Pada sistem lain, setelah

cat /dev/fd/5

cat mendapat fd yang merupakan duplikat dari fd 5, jadi masih dengan offset di akhir file.

Alasan mengapa ia bekerja lessadalah karena suatu alasan, lessmelakukan a lseek()pada fd ke awal file (apakah lseek(1); lseek(0)untuk menentukan apakah file tersebut dapat dicari atau tidak).

Di sini, Anda mungkin ingin memiliki fd untuk membaca dan satu untuk menulis jika Anda ingin keduanya memiliki offset yang berbeda:

exec 5< file 9>&1 > file

Atau Anda harus membuka kembali file jika masih ada, atau melakukan lseek()seperti yang lessdilakukannya.

ksh93dan zshsatu-satunya cangkang dengan lseek()operator bawaan :

cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin

Atau:

cat /dev/fd/5 5<#((0))  # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh
Stéphane Chazelas
sumber