Apakah pengalihan dengan `>>` sama dengan `>` ketika file target belum ada?

80

Pertimbangkan shell seperti Bash atau sh. Perbedaan mendasar antara >dan >>memanifestasikan dirinya dalam kasus ketika file target ada:

  • > memotong file ke ukuran nol, lalu menulis;
  • >> tidak terpotong, ia menulis (menambahkan) ke akhir file.

Jika file tidak ada itu dibuat dengan ukuran nol; kemudian ditulis untuk. Ini berlaku untuk kedua operator. Tampaknya operator setara ketika file target belum ada.

Benarkah itu?

Kamil Maciorowski
sumber

Jawaban:

107

tl; dr

Tidak. Pada >>dasarnya "selalu mencari ke ujung file" sambil >mempertahankan pointer ke lokasi tertulis terakhir.


Jawaban penuh

(Catatan: semua pengujian saya dilakukan pada Debian GNU / Linux 9).

Perbedaan lainnya

Tidak, mereka tidak setara. Ada perbedaan lain . Ini dapat memanifestasikan dirinya terlepas dari apakah file target ada sebelum atau tidak.

Untuk mengamatinya, jalankan proses yang menghasilkan data dan redirect ke file dengan >atau >>(misalnya pv -L 10k /dev/urandom > blob). Biarkan dijalankan dan ubah ukuran file (mis. Dengan truncate). Anda akan melihat bahwa >menjaga (tumbuh) diimbangi sambil >>selalu menambahkan sampai akhir.

  • Jika Anda memotong file ke ukuran yang lebih kecil (ukurannya bisa nol)
    • >tidak akan peduli, itu akan menulis di offset yang diinginkan seolah-olah tidak ada yang terjadi; tepat setelah memotong offset di luar akhir file, ini akan menyebabkan file untuk mendapatkan kembali ukurannya yang lama dan tumbuh lebih lanjut, data yang hilang akan diisi dengan nol (dengan cara yang jarang, jika mungkin);
    • >> akan ditambahkan ke ujung baru, file akan tumbuh dari ukuran terpotong.
  • Jika Anda memperbesar file
    • >tidak akan peduli, itu akan menulis di offset yang diinginkan seolah-olah tidak ada yang terjadi; hanya setelah mengubah ukuran offset di suatu tempat di dalam file, ini akan menyebabkan file berhenti tumbuh untuk sementara waktu, sampai offset mencapai ujung yang baru, maka file akan tumbuh secara normal;
    • >> akan menambahkan ke ujung baru, file akan tumbuh dari ukurannya yang diperbesar.

Contoh lain adalah menambahkan (dengan terpisah >>) sesuatu yang ekstra ketika proses pembuatan data sedang berjalan dan menulis ke file. Ini mirip dengan memperbesar file.

  • Proses menghasilkan dengan >akan menulis pada offset yang diinginkan dan menimpa data tambahan pada akhirnya.
  • Proses pembuatan dengan >>akan melewatkan data baru dan menambahkan melewatinya (kondisi ras dapat terjadi, dua aliran bisa disisipkan, masih tidak ada data yang harus ditimpa).

Contoh

Apakah itu penting dalam praktik? Ada pertanyaan ini :

Saya menjalankan proses yang menghasilkan banyak output di stdout. Mengirim semuanya ke file [...] Dapatkah saya menggunakan semacam program rotasi log?

Jawaban ini mengatakan solusinya adalah logrotatedengan copytruncateopsi yang bertindak seperti ini:

Potong file log asli di tempat setelah membuat salinan, alih-alih memindahkan file log lama dan secara opsional membuat yang baru.

Menurut apa yang saya tulis di atas, pengalihan dengan >akan membuat log terpotong besar dalam waktu singkat. Sparseness akan menghemat hari, tidak ada ruang disk yang signifikan yang harus terbuang. Namun demikian, setiap log berturut-turut akan memiliki semakin banyak nol di depannya yang sama sekali tidak perlu.

Tetapi jika logrotatemembuat salinan tanpa menjaga kesederhanaan, angka nol di depan ini akan membutuhkan lebih banyak ruang disk setiap kali salinan dibuat. Saya belum menyelidiki perilaku alat, mungkin cukup pintar dengan sparseness atau kompresi on the fly (jika kompresi diaktifkan). Namun nol hanya dapat menyebabkan masalah atau bersikap netral; tidak ada yang baik di dalamnya.

Dalam hal ini, >>alih-alih menggunakan >secara signifikan lebih baik, bahkan jika file target akan dibuat belum.


Performa

Seperti yang dapat kita lihat, kedua operator bertindak berbeda tidak hanya ketika mereka mulai tetapi juga nanti. Ini dapat menyebabkan beberapa perbedaan kinerja (halus?). Untuk saat ini saya tidak memiliki hasil pengujian yang berarti untuk mendukung atau menyanggahnya, tetapi saya pikir Anda tidak boleh secara otomatis menganggap kinerja mereka sama secara umum.

Kamil Maciorowski
sumber
9
Jadi >>pada dasarnya "selalu mencari ke ujung file" sambil >mempertahankan pointer ke lokasi tertulis terakhir. Tampaknya mungkin ada beberapa perbedaan kinerja yang halus dalam cara mereka bekerja juga ...
Mokubai
10
Pada tingkat panggilan sistem, >>gunakan O_APPENDbendera untukopen() . Dan sebenarnya, >menggunakan O_TRUNC, sementara >>tidak. Kombinasi O_TRUNC | O_APPENDjuga dimungkinkan, bahasa shell tidak menyediakan fitur itu.
ilkkachu
3
@jjmontes, sumber standarnya adalah POSIX: pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/... tetapi tentu saja manual Bash juga memiliki deskripsi tentang operator pengalihan, termasuk yang tidak standar yang didukungnya: gnu.org/ software / bash / manual / html_node / Redirections.html
ilkkachu
2
@ilkkachu Saya menemukan ini menarik, karena menjelaskan rincian tentang O_APPEND yang saya bertanya-tanya setelah komentar Anda :): stackoverflow.com/questions/1154446/…
jjmontes
1
@Mokubai, OS waras mana pun akan memiliki panjang file ketika terbuka, dan memeriksa bendera dan menggerakkan offset ke ujung hanya akan hilang di semua pembukuan lainnya. Mencoba meniru O_APPENDdengan lseek()masing write()- masing sebelum akan berbeda, akan ada overhead sistem panggilan tambahan. (Dan tentu saja itu tidak akan berhasil, karena proses lain mungkin ada write()di antaranya.)
ilkkachu