Apakah aman untuk mengarahkan ulang stdout dan stderr ke file yang sama tanpa salinan deskriptor file?

27

Saya memulai di direktori kosong.

$ touch aFile
$ ls
aFile

Lalu saya lsdua argumen, salah satunya tidak ada di direktori ini. Saya mengarahkan kedua aliran output ke file bernama output. Saya menggunakan >>untuk menghindari menulis secara bersamaan.

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

Yang sepertinya berhasil. Apakah ada bahaya untuk pendekatan ini?

exit_status
sumber
6
Itu suara cepat turun. Butuh lima detik. Bisakah Anda memberi tahu saya bagaimana Anda dapat menilai kelayakan pertanyaan saya begitu cepat? Dan lebih baik lagi, apa yang salah dengan itu sehingga saya bisa memperbaikinya?
exit_status
Mengapa Anda tidak menggunakan lebih banyak standar di ls aFile not_exist &>>outputsini? (Catatan, saya berasumsi Anda menggunakan bash .)
FedonKadifeli
5
Karena itu tidak membantu saya memahami apa yang saya tanyakan. Saya tahu cara mengarahkan stream ini ke file yang sama, bahkan untuk portable. Yang ingin saya ketahui adalah apakah ada yang salah dengan apa yang saya sarankan dalam pertanyaan. @FedonKadifeli
exit_status
1
@FedonKadifeli &>>BUKAN standar. Ini adalah sintaks yang ambigu dan ambigu yang bekerja secara berbeda di shell yang berbeda. Aku ingin tahu dari mana kalian mendapatkan barang-barangmu.
Paman Billy
4
Bash bukan standar . Mandat standar POSIX yang ls &>>foo ...harus diuraikan sebagai dua perintah ls &dan >>foo ..., dan ini adalah cara shell lain seperti /bin/shdari Ubuntu menguraikannya. Untuk itu menjadi usang, Anda dapat melihat di sini - meskipun saya tidak berpura-pura itu semacam otoritas. Anda dapat bertanya kepada bashpengelola apakah mereka mempertimbangkan untuk menggunakan ide yang bagus.
Paman Billy

Jawaban:

22

Tidak, tidak hanya seaman standar >>bar 2>&1.

Ketika Anda sedang menulis

foo >>bar 2>>bar

Anda membuka barfile dua kali dengan O_APPEND, membuat dua objek file yang sepenuhnya independen [1], masing-masing dengan statusnya sendiri (pointer, mode terbuka, dll).

Ini sangat berbeda dengan 2>&1yang hanya memanggil dup(2)panggilan sistem, dan membuat alias stderr dan stdout dipertukarkan untuk objek file yang sama.

Sekarang, ada masalah dengan itu:

O_APPENDdapat menyebabkan file rusak pada sistem file NFS jika lebih dari satu proses menambahkan data ke file sekaligus. Ini karena NFS tidak mendukung penambahan file, jadi kernel klien harus mensimulasikannya, yang tidak dapat dilakukan tanpa syarat ras.

Anda biasanya dapat mengandalkan probabilitas file seperti bardi foo >>bar 2>&1yang ditulis ke pada saat yang sama dari dua tempat terpisah yang cukup rendah. Tetapi dengan Anda, >>bar 2>>barAnda hanya meningkatkannya dengan selusin pesanan besar, tanpa alasan.

[1] "Buka Deskripsi File" dalam istilah POSIX.

mosvy
sumber
3
Secara formal, untuk file mode-append, aman . Masalah yang dikutip adalah bug di NFS yang membuatnya tidak cocok (non-POSIX-conforming) sebagai sistem file. Untuk kasus non-append mode, tidak pernah aman.
R ..
1
Itu tidak penting. Apendiks ganda OP tidak aman untuk digunakan (selain tidak ada gunanya sama sekali). Dan O_APPENDsemacam botch toh - cukup berat untuk diimplementasikan dengan benar.
Mosvy
Saya percaya kondisi ras NFS hanya antara klien yang berbeda. OS klien harus mengoordinasikan semua penulisan di antara prosesnya.
Barmar
@Barmar itu akan benar jika OS klien hanya peduli dengan tampilan file nfs sendiri. Tetapi ketika menulis ke file nfs dibuka O_APPEND, klien pertama-tama akan mengambil ukuran "nyata" file dari server ("revalidate" inode) dan kemudian melakukan pencarian + tulis + pembaruan inode dalam cache, dan hanya bagian terakhir adalah dilakukan di bawah kunci, yang berarti bahwa bagian pertama masih dapat mengambil ukuran basi dari server dan menimpa yang benar dari inode lokal / cache. Masalah yang sama dengan lseek(SEEK_END).
Mosvy
Saya masih tidak melihat bagaimana hal itu dapat menyebabkan kondisi balapan antara dua aliran pada klien yang sama. Kedua aliran harus merujuk ke inode cache lokal yang sama.
Barmar
22

Apa yang terjadi ketika Anda melakukannya

some_command >>file 2>>file

adalah yang fileakan dibuka untuk menambahkan dua kali. Ini aman untuk dilakukan pada sistem file POSIX. Tulisan apa pun yang terjadi pada file saat dibuka untuk ditambahkan akan terjadi pada akhir file, terlepas dari apakah data tersebut berasal dari aliran output standar atau aliran kesalahan standar.

Ini bergantung pada dukungan untuk operasi penulisan append atom di sistem file yang mendasarinya. Beberapa sistem file, seperti NFS, tidak mendukung penambahan atom. Lihat misalnya pertanyaan "Apakah file append atomic di UNIX?" Pada StackOverflow.

Menggunakan

some_command >>file 2>&1

akan bekerja bahkan pada NFS sekalipun.

Namun, menggunakan

some_command >file 2>file

tidak aman, karena shell akan memotong file output (dua kali) dan tulisan apa pun yang terjadi di kedua aliran akan menimpa data yang sudah ditulis oleh aliran lain.

Contoh:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

The hellostring tertulis pertama (dengan baris baru terminating), dan kemudian string abcdiikuti oleh baris baru ditulis dari standard error, Timpa hell. Hasilnya adalah string abcdengan baris baru, diikuti oleh apa yang tersisa dari echooutput pertama , odan baris baru.

Menukar keduanya di echosekitar luka menghasilkan hanya hellodalam file output sebagai string yang ditulis terakhir dan lebih panjang dari abcstring. Urutan pengalihan terjadi tidak masalah.

Akan lebih baik dan aman untuk menggunakan yang lebih idiomatis

some_command >file 2>&1
Kusalananda
sumber
1
Sementara itu berlaku untuk shell modern, itu tidak terjadi di shell Bourne atau Thomson (dari mana >>berasal), di mana >>akan terbuka untuk menulis dan mencari sampai akhir (saya kira karena O_APPEND belum ditemukan saat itu). Bahkan pada Solaris 10, /bin/sh -c '(echo a; echo b >&2) >> file 2>> file; cat file'keluaran b.
Stéphane Chazelas
@ StéphaneChazelas Apakah itu masalah dengan implementasi Solaris 10 sh, atau dengan sistem berkasnya?
Kusalananda
1
Itulah yang >>awalnya dilakukan, itu bukan pembukaan dengan O_APPEND, itu terbuka tanpa dan berusaha sampai akhir. Ini bukan masalah, itu apa yang dilakukan dan didokumentasikan untuk dilakukan.
Stéphane Chazelas
0

Itu tergantung apa yang ingin Anda capai. Terserah Anda untuk memutuskan apakah boleh memiliki kesalahan dalam file yang sama dengan output. Ini hanya menyimpan teks dalam file dengan fungsi shell yang memungkinkan Anda mengarahkan ulang seperti yang Anda inginkan. Tidak ada mutlak ya atau tidak. Karena semua yang ada di Linux dapat dilakukan dengan beberapa cara, ini adalah cara saya ls notExistingFile existingFile >> output 2>&1 Untuk menjawab pertanyaan: Dalam hal pengalihan itu sendiri, ya itu sangat aman.

malaikat
sumber
Ada lebih dari itu yang Anda katakan di sini. Latihan yang sama dengan >alih - alih >>akan menimpa beberapa karakter. Jadi bukan hanya shell memungkinkan saya untuk mengarahkan ulang, karena ketika saya mengarahkan ulang >, hasilnya berbeda. Jadi ada nuansa dengan >, apakah ada dengan >>?
exit_status
Ya itu akan berbeda. Seperti yang saya katakan itu tergantung pada tujuan Anda >- menimpa. >>- tambahkan
Malaikat