Hedef dosya henüz mevcut değilken `>>` `>` ile eşdeğerde yönlendirme var mı?


80

Bash ya da sh gibi bir kabuk düşünün. Hedef dosya olduğunda, arasındaki >ve arasındaki temel fark >>kendini gösterir:

  • > dosyayı sıfır boyutuna keser, sonra yazar;
  • >> kesmiyor, dosyanın sonuna yazar (ekler).

Dosya yoksa, sıfır boyutta oluşturulur; sonra yazılmış. Bu her iki operatör için de geçerlidir. Hedef dosya henüz bulunmadığında operatörler eşdeğer görünebilir.

Gerçekten mi?

Yanıtlar:


107

tl; Dr.

Hayır >>, temelde "her zaman dosyanın sonunu ara" >, son yazılan konuma bir işaretçi tutar.


Tam cevap

(Not: tüm testlerim Debian GNU / Linux 9'da yapıldı).

Başka bir farklılık

Hayır, eşdeğer değiller. Orada başka farkı. Hedef dosyanın önceden var olup olmamasından bağımsız olarak kendini gösterebilir.

Bunu gözlemlemek için, veri üreten bir işlemi çalıştırın ve >veya >>(örneğin pv -L 10k /dev/urandom > blob) ile bir dosyaya yönlendirin . Çalıştırmasına ve dosyanın boyutunu değiştirmesine izin verin (örn truncate. İle ). Her zaman sona >eklenirken (büyüyen) ofsetini koruduğunu göreceksiniz >>.

  • Dosyayı daha küçük bir boyuta keserseniz (sıfır boyutta olabilir)
    • >umursamayacak, hiçbir şey olmamış gibi istediği şekilde yazacak; ofsetin kesilmesinden hemen sonra, dosyanın sonunun ötesine geçmesi, bu dosyanın eski boyutunu geri kazanmasına ve daha da büyümesine neden olur; eksik veriler sıfırlarla (mümkünse seyrek) sıfırlarla doldurulur;
    • >> yeni sona eklenecek, dosya kesilmiş boyutundan itibaren büyüyecek.
  • Dosyayı büyütürseniz
    • >umursamayacak, hiçbir şey olmamış gibi istediği şekilde yazacak; boyutu değiştirdikten hemen sonra ofset, dosyanın içinde bir yerdedir; bu, ofset yeni sonuna ulaşana kadar dosyanın bir süre büyümesini durduracaktır, ardından dosya normal şekilde büyür;
    • >> yeni sona eklenecek, dosya büyütülmüş boyutundan büyüyecek.

Başka bir örnek, >>veri oluşturma işlemi çalışırken ve dosyaya yazarken, (ayrı olarak ) ekstra bir şeyler eklemektir. Bu, dosyayı büyütmeye benzer.

  • Üretme işlemi >, istenen ofsette yazacak ve sonunda ilave verilerin üzerine yazacaktır.
  • Oluşturma işlemi >>yeni verileri atlayacak ve ekleyecektir (yarış durumu oluşabilir, iki akış birleştirilebilir, yine de hiçbir verinin üzerine yazılmamalıdır).

Örnek

Uygulamada önemli mi? Orada bu soru :

Stdout'ta çok fazla çıktı üreten bir işlem yürütüyorum. Hepsini bir dosyaya gönderme [...] Bir tür günlük döndürme programı kullanabilir miyim?

Bu cevap çözüm olduğunu söylüyor logrotateile copytruncatebu gibi davranır seçeneği:

Eski günlük dosyasını taşımak ve isteğe bağlı olarak yeni bir tane oluşturmak yerine, bir kopya oluşturduktan sonra orijinal günlük dosyasını yerinde kesin.

Yukarıda yazdıklarıma göre, yeniden yönlendirmek >kesilmiş kütüğü çok kısa sürede büyütecektir. Seyreklik günü kurtaracak, kayda değer disk alanı israf edilmemelidir. Bununla birlikte, her ardışık kütüğün içinde, tamamen gereksiz olan, gittikçe daha fazla sayıda lider sıfır olacaktır.

Ancak logrotate, seyreklikten korunmaksızın kopyalar yaratırsa, bu baştaki sıfırların her kopya yapıldığında daha fazla disk alanına ihtiyacı olacaktır. Takımın davranışını araştırmadım, hareket halindeyken seyreklik veya sıkıştırma ile yeterince akıllı olabilir (eğer sıkıştırma etkinse). Yine de sıfırlar yalnızca soruna neden olabilir veya en iyi ihtimalle nötr olabilir; içlerinde iyi bir şey yok.

Bu durumda, >>yerine >hedef dosya henüz oluşturulacak olsa bile, bunun kullanılması önemli ölçüde daha iyidir.


Verim

Gördüğümüz gibi, iki operatör yalnızca başladığında değil, sonra da farklı davranıyor. Bu, bazı (ince?) Performans farkına neden olabilir. Şimdilik bunu destekleyecek ya da ispatlayacak anlamlı bir test sonucum yok, ancak performanslarının genel olarak aynı olduğunu varsaymamanız gerektiğini düşünüyorum.


9
Öyleyse >>, esasen “her zaman dosyanın sonunu ara” >, son yazılan konuma işaretçi tutar. Çalışma biçimlerinde bazı ince performans farkları var gibi görünüyor ...
Mokubai

10
Sistem çağrısı düzeyinde, bayrağını>> kullanır . Ve aslında, kullanır , ancak kullanmaz . Bunun bir kombinasyonu da mümkün olabilir, kabuk dili sadece bu özelliği sağlamıyor. O_APPENDopen()>O_TRUNC>>O_TRUNC | O_APPEND
ilkkachu

3
jjmontes, standart kaynak POSIX olacaktır: pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/… ancak elbette Bash'in kılavuzunda, standart dışı olanlar da dahil olmak üzere yönlendirme operatörleri hakkında açıklamalar da var: gnu.org/ software / bash / manual / html_node / Redirections.html
ilkkachu

2
@ilkkachu Bu yorumdan sonra merak ettiğim O_APPEND ile ilgili ayrıntıları anlattığım için ilgimi çeken bir şey buldum :): stackoverflow.com/questions/1154446/…
jjmontes 23:18

1
@Mokubai, Herhangi bir mantıklı işletim sistemi açıkken eldeki dosya uzunluğunu elinde tutar ve bir bayrağı kontrol etmek ve ofseti sonuna kadar taşımak diğer tüm defter tutma işlemlerinde kaybolur. Her O_APPENDbiriyle lseek()önceden bir öykünmek denemek write()farklı olurdu, ama ek sistem çağrısı yükü olurdu. (Tabii ki işe write()
yaramazdı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.