2011-10-28 16 views
16

Bir dosyayı sıralamaya ve sıralı çıktıyı kendi kendine saklamaya çalıştığımda, buNeden "file1> file1" işini yapmıyor?

sort file1 > file1; 

gibi, dosyanın1 içeriği tamamen siliniyor, oysa aynı şeyi 'tee' komutuyla yapmaya çalıştığımda Bu

sort file1 | tee file1; 

gayet çalışır gibi:, yani o çıktıyı sıralı üzerine.Yapıyor [ed yalnızca şanslı zamanlama ile küçük dosyalar için "çalışıyor", büyük olanlar ya da yararsız süreç planlaması ile kayıp veri neden olur] dosya1'in kendi içinde ve ayrıca standart çıktıda gösteriliyor.

Birisi neden ilk durumun çalışmadığını açıklayabilir mi?

+0

Dup (http://superuser.com/q/142504/7542) – outis

cevap

13

'>' Yeniden yönlendirme, kesme işlemini gerektirdiğinden ve dosyaya yeniden yönlendirmeden önce tüm çıktıyı sort bellekte tutmayı engellemek için çalışmaz, bash keser ve sort çalıştırılmadan önce çıktıyı yönlendirir. Böylece, sort dosyasının içeriği okuma şansı olmadan önce file1 dosyasının içeriği kesilecektir.

+0

'Dosyaya yeniden yönlendirmeden önce bellekte tüm çıktı miktarını korumaktan kaçınmamak' ve 'bash'a özgü değil. '>' Tanımlı önceliği, programın yürütülmesinden önce, tüm kabuklarda olduğu gibi basitleştirildiği anlamına gelir. – EJP

1

İkinci durumda, satır, içeriği zaten okuduktan sonra dosyayı açar.

+0

'tee' onun dosyasını açar 'sort', dosyayı açtığı zamana göre belirli bir süre belirsiz. Bazen şansın olur, bazen yapmazsın. 'Sıralama' 'nın tüm içeriği okuduğuna, sadece dosyayı ilk açtığına gerek yoktur. – EJP

1

Yönlendirme daha yüksek önceliğe sahiptir. Yani ilk durumda> dosya1 ilk önce yürütür ve dosyayı boşaltır.

4

Beklediğiniz gibi çalışmak için bu komutlardan herhangi birine bağımlı olmak akıllıca olmaz. Bu öyle sonra dosyayı okuma problemini önler

sort file1 > file1.tmp && mv file1.tmp file1 

:

yerde bir dosyayı değiştirmek için bir yol daha sonra, yeni bir dosyaya değiştirilmiş versiyonu yazma özgün adıyla yeni dosyayı yeniden adlandırmak için Kısmen değiştirilmiş, sonuçların dağınık olması muhtemeldir. Aynı zamanda hatasız bir şekilde hatalarla uğraşmayı mümkün kılar; Dosya N bayt uzunsa ve dosya sisteminde yalnızca N/2 bayt boş alan varsa, geçici dosyayı oluştururken hatayı algılayabilir ve yeniden adlandırma yapamazsınız.

Yoksa o zaman okumak ve aynı adla yeni bir dosyaya yazma, özgün dosyayı yeniden adlandırabilirsiniz:

mv file1 file1.bak && sort file1.bak > file1 

Bazı komutlar, örneğin (perl ve sed hem yerde dosyaları değiştirmek için seçenekler vardır sahip -i seçenekleri (en sed -i seçeneğin sözdizimi değişebilir unutmayın) Ama bu seçenekler geçici dosyalar oluşturarak çalışır;.. sadece dahili olarak bitti

+3

Güzel - ama 'sort -o dosya1 dosya1 'çok daha basit ve daha güvenli. –

16

kişi açıkladığı gibi, sorun I/o yönlendirmesi yapılıyor olmasıdır sort c'den önce ommand yürütülür, bu yüzden dosya sort okumadan önce bir şans alır. Biraz düşünürseniz, neden açık - nedeni kabuk G/Ç yönlendirmesini işler ve komutu çalıştırmadan önce bunu yapmalıdır.

sort komut hep 'vardır (en azından Sürüm 7 UNIX beri) giriş dosyalarının birine çıkışına güvenli hale getirmek için bir -o seçeneği desteklenen:

sort -o file1 file1 file2 file3 

tee ile hile zamanlamasına bağlıdır ve şans (ve muhtemelen küçük bir veri dosyası). Bir megabayt veya daha büyük bir dosyaya sahip olsaydınız, en azından kısmen tee komutuyla klobber olmasını beklerdim. Yani, dosya yeterince büyükse, tee komutu çıktı için dosyayı açar ve sort okumayı bitirmeden önce bunu keser. yönlendirme operatörü (> veya >>) kullanırken çünkü

+2

+1. Her zaman man sayfaları okumak için öder –

1

ilk komutu çalışmıyor (sort file1 > file1), kabuk sort komut bile çağrılmadan önce daha yüksek önceliğe sahip olduğundan /, dosyayı keser oluşturur.

İkinci komut çalışır (sort file1 | tee file1), çünkü sort önce dosyadan satırlar okur, sonra sıralı verileri standart çıktıya yazar. diğer benzer komutu kullanırken

Yani, okuma ve aynı dosya içine yazarken yönlendirme operatörü kullanılarak kaçınmalısınız, ama bunun için ilgili yerinde editörleri kullanmalıdır (örn ex, ed, sed): örneğin,

ex '+%!sort' -cwq file1 

veya sponge gibi diğer utils'i kullanın.

Neyse ki sort için (@Jonathan önerdiği gibi) dosyaya sonuçları yazmak -o parametre vardır, bu nedenle çözüm bellidir: sort -o file1 file1.

-2

Bu sıralamak ve orijinal dosyaya geri depolayacak bu yöntemi

sort file1 -o file1 

kullanabilirsiniz. Ayrıca, yinelenen çizgi kaldırmak için bu komutu kullanabilirsiniz: [? SIRALAMA dosyamı boşaltır] arasında

sort -u file1 -o file1 
+0

Zaten belirtilen yıllar önce. –

+0

Ve gerçek soruya cevap vermiyor. – EJP

İlgili konular