Stdout ve stderr'i dosya tanımlayıcı kopyaları olmadan aynı dosyaya yönlendirmek güvenli midir?


27

Boş dizinde başlıyorum.

$ touch aFile
$ ls
aFile

Sonra ls, biri bu dizinde olmayan iki argüman var. Her iki çıktı akışını da adlandırılmış bir dosyaya yönlendiririm output. >>Aynı anda yazmaktan kaçınmak için kullanıyorum .

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

Bu iş gibi görünüyor. Bu yaklaşımın herhangi bir tehlikesi var mı?


6
Bu hızlı bir oylama oldu. Beş saniye sürdü. Sorumun önemini bu kadar çabuk nasıl değerlendirebileceğinizi söyleyebilir misiniz? Ve daha da iyisi, onu geliştirmek için yanlış olan ne?
exit_status

Neden ls aFile not_exist &>>outputburada daha fazla standart kullanmıyorsun ? (Not, bash kullandığınızı farz ediyorum .)
FedonKadifeli

5
Çünkü bu ne sorduğumu anlamama yardımcı olmuyor. Bu akışları aynı dosyaya, hatta taşınabilir olarak nasıl yönlendireceğimi biliyorum. Bilmek istediğim, soruda önerdiklerimde yanlış bir şey olup olmadığı. @FedonKadifeli
exit_status

1
@ FedonKadifeli &>>standart değildir. Farklı mermilerde farklı şekilde çalışan, TANIMLI, belirsiz bir sözdizimidir. Eşyalarını nereden aldığınızı merak ediyorum.
Billy Amca

4
Bash bir standart değildir . POSIX standardı görev ls &>>foo ...iki komutlarını olarak çözümlenen gerektiğini ls &ve >>foo ...ve bu diğer kabuklar gibi yoludur /bin/shUbuntu onu ayrıştırdığınızdan. Kullanımdan kaldırıldığı için buraya bakabilirsiniz - bunun bir tür otorite olduğunu iddia etmiyorum. Ancak bashbakıcılara bunu iyi bir fikir kullanmayı düşünüp düşünmediklerini sorabilirsiniz .
Billy Amca

Yanıtlar:


22

Hayır, standart kadar güvenli değil >>bar 2>&1.

Sen yazarken

foo >>bar 2>>bar

bardosyayı iki kez açarak O_APPEND, her biri kendi durumuyla (işaretçi, açık modlar, vb.) iki tamamen bağımsız dosya nesnesi [1] oluşturarak açıyorsunuz .

Bu 2>&1sadece dup(2)sistem çağrısını çağırmaktan farklıdır ve aynı dosya nesnesi için stderr ve stdout değişken takma adlarını yapar.

Şimdi, bununla ilgili bir sorun var:

O_APPENDBirden fazla işlem bir defada bir dosyaya veri eklerse, NFS dosya sistemlerinde bozuk dosyalara yol açabilir. Bunun nedeni, NFS'nin bir dosyaya eklemeyi desteklememesidir, bu nedenle istemci çekirdeği, bir yarış koşulu olmadan yapılamayacak şekilde onu simüle etmek zorundadır.

Genellikle gibi dosyanın olasılık güvenebilirsiniz bariçinde foo >>bar 2>&1oldukça düşük olması iki ayrı yerden aynı anda yazılıyor. Fakat sizin >>bar 2>>bartarafınızdan, herhangi bir sebep olmadan, bir düzine büyüklük düzeni ile arttırdınız.

[1] POSIX dilindeki "Dosya Tanımlarını Aç".


3
Resmen, ekleme modu dosyaları için güvenlidir . Alıntılanan sorun, NFS'de bir dosya sistemi olarak uygun olmayan (POSIX uyumlu değil) kılan bir hatadır . Bununla birlikte, son moda olmayan durum için de hiçbir zaman güvenli değildir.
R. ..

1
Bu önemsiz. OP'nin çift ekinin kullanımı güvenli değildir (tamamen anlamsız olmasına ek olarak). Ve O_APPENDyine de bir botch - doğru uygulamak için oldukça zahmetli.
mosvy

NFS yarış koşulunun sadece farklı müşteriler arasında olduğuna inanıyorum. İstemci işletim sistemi işlemleri arasındaki tüm yazıları koordine etmelidir.
Barmar

@Barmar, eğer istemci işletim sistemi sadece bir nfs dosyası ile ilgili görüşlerini önemserse doğru olurdu. Ancak, nfs dosyasına açıldığında O_APPEND, istemci ilk önce dosyanın "gerçek" boyutunu sunucudan alır (inode'u yeniden doğrular) ve daha sonra seek + write + cached inode güncellemesini yapar ve yalnızca son bölüm Kilitler altında yapılır, bu ilk bölümün sunucudan eski bir boyut alabildiği ve doğru olanı yerel / önbellekteki inode'dan geçersiz kılabileceği anlamına gelir. Aynı sorun lseek(SEEK_END).
mosvy

Aynı müşterideki iki akış arasında bunun nasıl yarış koşullarına neden olabileceğini hala anlamadım. Her iki akış da aynı yerel önbelleğe alınmış inode'a başvurmalıdır.
Barmar

22

Ne yaparsan ne olur

some_command >>file 2>>file

yani fileiki kere ekleme açılacaktır. POSIX dosya sisteminde yapmak güvenlidir. Eklemek için açıldığında dosyaya olan herhangi bir yazma, verilerin standart çıkış akışının veya standart hata akışının üzerinden gelmesine bakılmaksızın dosyanın sonunda ortaya çıkar.

Bu, temel dosya sistemindeki atomik ekleme yazma işlemleri için desteğe dayanır. NFS gibi bazı dosya sistemleri atomik eklemeyi desteklememektedir. Örneğin, StackOverflow'ta "Dosya UNIX'te atomik ek mi?"

kullanma

some_command >>file 2>&1

NFS bile olsa çalışırdı.

Ancak, kullanarak

some_command >file 2>file

Kabuk çıkış dosyasını kısaltacağından (iki kez) güvenli olacağından ve herhangi bir akışta olan herhangi bir yazım diğer akış tarafından önceden yazılmış verilerin üzerine yazacaktır .

Örnek:

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

helloDize (sonlandırıcı yeni satır ile) ilk yazılır ve sonra dize abcsonrasında bir yeni satır üzerine yazarak, standart hata yazılır hell. Sonuçta, abcyeni echoçıktısı olan ove ardından ilk çıktının kalanı olan bir ve yeni satır olan dizedir .

İki takas echoyalnızca yaklaşık yara üretmek helloo dize son yazılı ve daha uzun olduğu gibi çıkış dosyasında abcdize. Yönlendirmelerin gerçekleştiği sıra önemli değildir.

Daha deyimsel kullanmak daha iyi ve daha güvenli olurdu

some_command >file 2>&1

1
Bu modern kabukları için geçerli olsa da, Bourne veya Thomson kabuğundaki (nereden >>geliyor) durum böyle değildi , nerede >>yazmaya ve açmaya son vereceklerdi (sanırım O_APPEND henüz o zamanlar icat edilmedi). Solaris 10'da bile /bin/sh -c '(echo a; echo b >&2) >> file 2>> file; cat file'çıktılar b.
Stéphane Chazelas

@ StéphaneChazelas Solaris 10'un shveya onun sistemiyle ilgili bir sorun mu var?
Kusalananda

1
Ne en Yani >>aslen yapıyordu, bu olmaması için O_APPEND ile açılış değildi, olmadan açma ve sonuna kadar arama oldu. Bu o kadar da önemli bir konu değil, yaptığı şeydi ve yapılması belgelenmişti.
Stéphane Chazelas

0

Ne elde etmek istediğine bağlı. Çıktıyla aynı dosyada hataların olup olmadığına karar vermek size kalmış. Bu sadece metni istediğiniz şekilde yönlendirmenize izin veren kabuğun işlevselliğine sahip bir dosyaya kaydetmektir. Mutlak evet ya da hayır yoktur. Linux'ta her şey birkaç şekilde yapılabilir, bu benim yolum ls notExistingFile existingFile >> output 2>&1 Soruyu cevaplamak: Yönlendirme açısından, evet, tamamen güvenli.


Burada söylediklerinden daha fazlası var. Bunun >yerine aynı alıştırma >>bazı karakterlerin üzerine yazacaktır. Bu yüzden sadece kabuk yeniden yönlendirmeme izin vermiyor, çünkü yeniden yönlendirdiğimde >sonuç farklı. Yani nüanslar var >, hiç var >>mı?
exit_status

Evet farklı olacak. Söylediğim gibi, amacına bağlı >- üzerine yaz. >>- Eklemek
Angel
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.