> & -> / dev / null değerinden daha mı verimli?


58

Dün , kabuğundaki (en azından ) "aynı sonuç" olduğunu söyleyen bu SO yorumunu okudum .bash>&->/dev/null

Bu yorum aslında ABS rehberine bilgisinin kaynağı olarak atıfta bulunuyor . Ancak bu kaynak >&-sözdiziminin "dosya tanımlayıcılarını kapattığını" söylüyor .

Bir dosya tanıtıcısını kapatma ve onu boş cihaza yeniden yönlendirmenin iki eyleminin tamamen eşdeğer olup olmadığı bana açık değil. Yani benim sorum şu: onlar mı?

Onun yüzeyinde bir tanımlayıcıyı kapatmanın bir kapıyı kapatmaya benziyor ama boş bir aygıta yönlendirmek limbo'ya bir kapı açıyor! İkisi de aynı görünmüyor çünkü kapalı bir kapı görürsem, hiçbir şey atmaya çalışmayacağım ama açık bir kapı görürsem başarabileceğimi farzedeceğim.

Başka bir deyişle, hep merak etmişimdir >/dev/nullaraçlar cat mybigfile >/dev/nullaslında dosyanın her byte işlemek ve yazardı o kadar /dev/nullunutuyor hangi. Öte yandan kabuk kapalı bir dosya tanıtıcı karşılaşırsa, sanırım eğilimindedir (ama emin değilim) soru olmadığını kalır gerçi sadece, bir şey yazmak olmaz cathala olacaktır okumak her byte.

Bu yorum aynı diyor >&-ve >/dev/null" aynı " olmalı , ama bana çok yankıcı bir cevap değil. Standart veya kaynak çekirdekli bazı referans ile daha yetkili bir cevap istiyorum ya da değil ...


Eğer hayırsever olmak istersem, yorumun aynı şekilde uygulandığı anlamına gelmediğini, ikisinin de programın çıktısını görmesini engellemenin aynı sonuca sahip oldukları anlamına gelmediğini söyleyebilirim.
Barmar

Yanıtlar:


71

Hayır, kesinlikle yok dosya tanımlayıcıları 0, 1 ve 2 kapatmak istiyor.

Bunu yaparsanız, uygulama ilk kez bir dosya açtığında, stdin / stdout / stderr ...

Örneğin, eğer:

echo text | tee file >&-

Ne zaman tee(BusyBox gibi en azından bazı uygulamaları, ') yazmak için dosyayı açar, bu dosya tanımlayıcı 1 (stdout'ta) üzerinde açık olacaktır. Böylece iki kez teeyazacaksınız :textfile

$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "text\n", 8193)                 = 5
write(1, "text\n", 5)                   = 5
write(1, "text\n", 5)                   = 5
read(0, "", 8193)                       = 0
exit_group(0)                           = ?

Bunun güvenlik açıklarına neden olduğu bilinmektedir. Örneğin:

chsh 2>&-

Ve chsh(bir setuid uygulama) içine hata mesajları yazma ile sonuçlanabilir /etc/passwd.

Bazı araçlar ve hatta bazı kütüphaneler buna karşı korumaya çalışır. Mesela, GNU teedosya tanımlayıcısını bir üste taşıyacaktır, eğer yazmak için açtığı dosyalara 0, 1, 2 atanmışsa, meşgul kutusu teeolmaz.

Çoğu araç stdout'a yazamıyorlarsa (örneğin açık değil), stderr'de (yerelleştirme dosyalarını açmak ve ayrıştırmak için fazladan işlem yapmak anlamına gelen kullanıcının dilinde) bir hata mesajı rapor ederler. önemli ölçüde daha az verimli olacak ve muhtemelen programın başarısız olmasına neden olacaktır.

Her durumda, daha verimli olmayacak. Program hala write()sistem çağrısı yapacak . İlk başarısız write()sistem çağrısından sonra program stdout / stderr'ye yazmayı bırakırsa , ancak programlar genellikle bunu yapmazsa daha verimli olabilir . Genelde bir hatayla çıkarlar veya denemeye devam ederler.


4
Nihai paragrafın en üstünde olsaydı (OP'nin sorusunu en doğrudan cevaplayan şey olduğu için) bu cevabın daha da iyi olacağını düşünüyorum ve daha sonra işe yarasa bile neden kötü bir fikir olduğunu tartışmaya devam etti. Ama onu alıp, bir oyum olsun. ;)
24:14 CVn

@ StéphaneChazelas: Michael'in dediği gibi, en üstteki son parayı beklerdim, ama açıklığa kavuşturduğun için teşekkürler, aslında sadece sorun çıkarır. Öyleyse yardımcı bir soru, bir FD'yi kapatmak ne zaman faydalı olacak? Yoksa bunu ayrı bir soru olarak mı sormalıyım?
jamadagni


1
@jamadagni Stéphane tarafından verilen bağlantı soruyu cevaplamazsa, iki yöntemin göreceli etkinliği ile doğrudan ilgili olmadığı için ayrı bir sorunun başlangıcı gibi geldiğini söyleyebilirim.
24:14

1
Stephane'nin bu önemli güvenlik uyarısıyla başladığını ve son paragrafın üstünde olsaydı daha az görünür olacağı için minnettarım. Benden +1.
Olivier Dulac

14

Eğer IOW Hep merak etmişimdir >/dev/nullaraçlar cat mybigfile >/dev/nullaslında dosyanın her byte işlemek ve yazardı o kadar /dev/nullunutuyor hangi.

Sorunuza tam bir cevap değil, ama evet, yukarıdaki işler.

catadlandırılmış dosyaları / dosyaları veya hiçbir dosya adlandırılmamışsa standart girişi okur ve standart çıkışına , belirtilen son dosyada (standart girdi dahil) bir EOF ile karşılaşana kadar içeriğini çıkarır. Bu onun işi.

Ekleyerek >/dev/nullstandart çıktıyı / dev / null dizinine yönlendiriyorsunuz. Bu, içinde yazılı olan herhangi bir şeyi çöpe atan (ve hemen EOF'u okuduğunda döndüren) özel bir dosyadır (bir cihaz düğümü). G / Ç yönlendirmesinin her bir uygulama tarafından değil, kabuk tarafından sağlanan bir özellik olduğunu ve / dev / null adında büyülü bir şey olmadığını , yalnızca çoğu Unix benzeri sistemde ne olduğunu unutmayın .

Cihaz düğümlerinin belirli mekaniğinin işletim sisteminden işletim sistemine göre değiştiğine de dikkat etmek önemlidir, ancak cat (GNU sisteminde coreutils anlamına gelir) platformlar arasıdır (aynı kaynak kodun en azından Linux'ta çalışması gerekir ve Hurd) ve dolayısıyla belirli işletim sistemi çekirdeklerine bağımlılıklar alamaz. Ek olarak, bir / dev / null takma adı oluşturduğunuzda (Linux'ta bu, aynı ana / küçük cihaz numarasına sahip bir cihaz düğümü anlamına gelir) başka bir adla çalışır. Ve her zaman etkili bir şekilde aynı şekilde davranan başka bir yere yazma vakası vardır (örneğin, / dev / zero).

O şöyle cat/ dev / null özel özelliklerinin farkında değildir ve gerçekten de muhtemelen ilk etapta yönlendirme habersiz olmakla hala tam olarak aynı işi gerçekleştirmek gerekir: o adlandırılmış dosyaları okur ve içeriğini çıkarır / this dosyaları standart çıktılarına. Standart çıktının catbir boşluğa girmesi, catkendisinin ilgilendiği bir şey değildir .


2
Cevabınızı uzatmak için: Evet, her baytın belleğe okunmasına cat mybigfile > /dev/nullneden olacaktır . Ve, her bayt için arayacak . Programın haberi olmadan , kesinlikle hiçbir şey yapmayacak (bazı önemsiz defter tutma hariç). Yazmak için her byte işlem gerektirmez. catbigfilenwrite(1, buffer, n)catwrite/dev/null
G-Man

2
/ Dev / null aygıtının Linux çekirdeği kaynağını okuduğumda uçup gittiğimi hatırlıyorum. Orada, detaylı bir serbest sistem (tamponlar, vb.) Olmasını bekliyordum, ama, hayır, bu temelde bir geri dönüş ().
Brian Minton

4
@ G-Man: Her durumda bunun doğru olacağını garanti edebileceğinizi bilmiyorum. Şimdi kanıt bulamıyorum, ancak kaynak dosyanın büyük parçalarını hafızaya alarak ve sonra haritalanmış bölgeyi çağırarak işe yarayacak ya catda cpbunun bazı uygulamalarını hatırlıyorum . Yazmış olsaydınız , çağrı kaynak dosyadaki sayfalarda hata olmadan bir kerede geri dönerdi, bu yüzden asla diskten okunmazdı. mmapwrite()/dev/nullwrite()
Nate Eldredge

2
Ayrıca, GNU gibi bir şey catbirçok platformda çalışır, ancak kaynak koduna geçici bir bakış çok sayıda #ifdefs gösterecektir : kelimenin tam anlamıyla, tüm platformlarda çalışan aynı kod değildir ve bol miktarda sisteme bağlı bölümler vardır.
Nate Eldredge

@NateEldredge: İlginç nokta, ama ben sadece Michael'ın cevabı üzerine kuruyordum, bu yüzden Michael ile çeliştiğiniz kadar benimle çelişmiyorsunuz.
G-Man
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.