Buradaki herkesin tüm metin dosyalarının bir satırsonu ile bitmesi gerektiği fikrini bildiklerini düşünüyorum. Yıllardır bu "kuralı" tanıyorum ama hep merak ettim - neden?
Buradaki herkesin tüm metin dosyalarının bir satırsonu ile bitmesi gerektiği fikrini bildiklerini düşünüyorum. Yıllardır bu "kuralı" tanıyorum ama hep merak ettim - neden?
Yanıtlar:
Çünkü POSIX standardı bir hattı şu şekilde tanımlar :
- 3.206 Hattı
- Sıfır veya daha fazla <newline> karakterin yanı sıra sonlandırıcı <newline> karakteri.
Bu nedenle, yeni satır karakteri ile bitmeyen satırlar gerçek satır olarak kabul edilmez. Bu nedenle, bazı programlar, yeni satır sonlandırılmamışsa dosyanın son satırını işlemede sorun yaşar.
Bir terminal emülatörü üzerinde çalışırken bu kılavuzun en az bir zor avantajı vardır: Tüm Unix araçları bu kuralı bekler ve onunla çalışır. Örneğin, dosyaları ile birleştirirken cat
, yeni satır tarafından sonlandırılan bir dosya, aşağıdakileri içermeyenden farklı bir etkiye sahip olacaktır:
$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz
Ve önceki örneğin de gösterdiği gibi, dosyayı komut satırında görüntülerken (örn. Yoluyla more
), yeni satır sonlandırılmış bir dosya doğru görüntüyle sonuçlanır. Yanlış sonlandırılmış bir dosya bozuk olabilir (ikinci satır).
Tutarlılık için, bu kurala uymak çok yararlıdır - aksi takdirde varsayılan Unix araçlarıyla uğraşırken ekstra iş yapmanız gerekir.
Başka bir şekilde düşünün: Satırlar satırsonu tarafından sonlandırılmazsa, cat
yararlı gibi komutlar oluşturmak çok daha zordur: dosyaları birleştirmek için nasıl komut verirsiniz?
b.txt
ve c.txt
?Tabii ki bu çözülebilir, ancak cat
daha karmaşık (konumsal komut satırı argümanları ekleyerek) kullanımını yapmanız gerekir cat a.txt --no-newline b.txt c.txt
ve şimdi her dosya yerine komut diğer dosyalarla nasıl yapıştırılacağını kontrol eder. Bu neredeyse kesinlikle uygun değil.
… Veya sonlandırılmak yerine devam etmesi gereken bir çizgiyi işaretlemek için özel bir sentinel karakteri tanıtmanız gerekir. Şimdi, ters çevrilmiş (satır sonlandırma karakteri yerine satır devamı) dışında POSIX'teki durumla aynı kaldınız.
Şimdi, POSIX uyumlu olmayan sistemlerde (günümüzde çoğunlukla Windows'dur), mesele tartışmalıdır: dosyalar genellikle bir satırsonu ile bitmez ve bir satırın (gayri resmi) tanımı örneğin “ satır satırlarla ayrılmış metin ” olabilir (vurguyu not edin). Bu tamamen geçerlidir. Bununla birlikte, yapılandırılmış veriler için (örn. Programlama kodu) ayrıştırmayı en az karmaşık hale getirir: genellikle ayrıştırıcıların yeniden yazılması gerektiği anlamına gelir. Bir ayrıştırıcı başlangıçta POSIX tanımı göz önünde bulundurularak yazıldıysa, ayrıştırıcıdan ziyade belirteç akışını değiştirmek daha kolay olabilir - başka bir deyişle, girdinin sonuna bir “yapay yeni satır” belirteci ekleyin.
cat
hem kullanışlı hem de tutarlı bir şekilde araç yazmayı çok daha zorlaştırır .
Her satır, son satır da dahil olmak üzere yeni satır karakteri ile sonlandırılmalıdır. Bazı programlar, yeni satır sonlandırılmamışsa dosyanın son satırını işlemede sorun yaşar.
GCC , dosyayı işleyemediği için değil , standardın bir parçası olması gerektiği için uyarır .
C dili standardı, boş olmayan bir kaynak dosyasının, hemen ters eğik çizgi karakteri ile başlamaması gereken yeni satır karakteriyle sona ereceğini söylüyor.
Bu bir "irade" cümlesi olduğundan, bu kuralın ihlali için bir teşhis mesajı yayınlamalıyız.
Bu, ANSI C 1989 standardının 2.1.1.2 bölümünde yer almaktadır. ISO C 1999 standardının (ve muhtemelen ISO C 1990 standardının) Bölüm 5.1.1.2'si.
Referans: GCC / GNU posta arşivi .
wc -l
, yeni satır sonlandırılmamışsa dosyanın son satırını saymaz. Ayrıca, cat
ilk dosyanın son satırı yeni satır sonlandırılmamışsa, bir dosyanın son satırını bir sonraki dosyanın ilk satırı ile birleştirir. Sınırlayıcı olarak yeni satırlar arayan hemen hemen her program bunu bozma potansiyeline sahiptir.
wc
olan daha önce de bahsedildiği ....
cat
ve wc
)?
Bu cevap, görüşten ziyade teknik bir cevap girişimidir.
POSIX safları olmak istiyorsak, bir satırı şu şekilde tanımlarız:
Sıfır veya daha fazla <newline> karakterin yanı sıra sonlandırıcı <newline> karakteri.
Kaynak: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
Eksik satır:
Dosyanın sonunda bir veya daha fazla <newline> olmayan karakter dizisi.
Kaynak: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
Şu şekilde bir metin dosyası:
Sıfır veya daha fazla satır halinde düzenlenmiş karakterler içeren bir dosya. Satırlar NUL karakter içermez ve hiçbiri <newline> karakteri de dahil olmak üzere {LINE_MAX} bayt uzunluğunu aşamaz. POSIX.1-2008 metin dosyaları ve ikili dosyalar arasında ayrım yapmasa da (ISO C standardına bakın), çoğu yardımcı program metin dosyaları üzerinde çalışırken yalnızca öngörülebilir veya anlamlı çıktı üretir. Bu tür kısıtlamaları olan standart yardımcı programlar, STDIN veya INPUT FILES bölümlerinde her zaman "metin dosyaları" belirtir.
Kaynak: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
Aşağıdaki gibi bir dize:
İlk boş bayt tarafından ve bu son bayt dahil sonlandırılmış bir bayt dizisi.
Kaynak: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
Bundan sonra, herhangi bir sorunla potansiyel olarak karşılaşacağımız tek zamanın , bir dosya satırı veya bir metin dosyası olarak bir dosya kavramıyla uğraşmamızdır (bir metin dosyasının sıfır organizasyon olması) veya daha fazla satır ve bildiğimiz bir satır <newline> ile sonlanmalıdır).
Tipik bir örnek: wc -l filename
.
Gönderen wc
kılavuzuna okuyoruz:
Satır, <newline> karakteriyle ayrılmış karakter dizesi olarak tanımlanır.
JavaScript, HTML ve CSS dosyalarına metin dosyaları olmalarının etkileri nelerdir?
Tarayıcılarda, modern IDE'lerde ve diğer ön uç uygulamalarında EOF'ta EOL'yi atlamakla ilgili bir sorun yoktur. Uygulamalar dosyaları düzgün şekilde ayrıştırır. Tüm İşletim Sistemleri POSIX standardına uygun olmadığından, dosyaları POSIX standardına (veya herhangi bir OS seviyesi standardına) göre işlemek, işletim sistemi olmayan araçların (örn. Tarayıcılar) pratik olmayacaktır.
Sonuç olarak, bir UNIX işletim sisteminde çalışıyor olsa da, EOF'daki EOL'nin uygulama düzeyinde neredeyse hiçbir olumsuz etkisi olmayacağından emin olabiliriz.
Bu noktada, istemci tarafında JS, HTML, CSS ile uğraşırken EOF'da EOL atlamanın güvenli olduğunu söyleyebiliriz. Aslında, <newline> içermeyen bu dosyalardan herhangi birini küçültmenin güvenli olduğunu belirtebiliriz.
Bunu bir adım öteye taşıyabilir ve NodeJS söz konusu olduğunda, POSIX standardına uygun olarak POSIX uyumlu olmayan ortamlarda çalışabileceğini söyleyebiliriz.
O zaman ne kaldı? Sistem düzeyinde takımlama.
Bu, ortaya çıkabilecek tek sorunların, işlevlerini POSIX'in semantiğine uymaya çalışan araçlarla ilgili olduğu anlamına gelir (örneğin, gösterildiği gibi bir çizginin tanımı wc
).
Yine de, tüm mermiler POSIX'e otomatik olarak yapışmaz. Örneğin Bash, POSIX davranışını varsayılan olarak kullanmaz. Etkinleştirmek için bir geçiş vardır: POSIXLY_CORRECT
.
EOL'nin <newline> olmasının değeri üzerine düşünülen yiyecekler: https://www.rfc-editor.org/old/EOLstory.txt
Takım pistinde kalmak, tüm pratik amaçlar ve amaçlar için şunu düşünelim:
EOL'si olmayan bir dosyayla çalışalım. Bu yazıda, bu örnekteki dosya EOL içermeyen küçültülmüş bir JavaScript'tir.
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js
$ cat x.js y.js > z.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 x.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 y.js
-rw-r--r-- 1 milanadamovsky 15810 Aug 14 23:18 z.js
cat
Dosya boyutunun, tek tek parçalarının toplamı olduğuna dikkat edin . JavaScript dosyalarının birleştirilmesi JS dosyaları için bir endişe kaynağıysa, her JavaScript dosyasını noktalı virgülle başlatmak daha uygun bir sorundur.
Bu iş parçacığında başka birisinin de belirttiği gibi: cat
çıktısı iki yerine yalnızca bir satır haline gelen iki dosya istiyorsanız ? Başka bir deyişle, cat
yapması gerekeni yapar.
man
Arasında cat
sadece EOF'a girdi okuma bahseder değil, <satır>. -n
Anahtarının cat
ayrıca , sayının 1'de ( . ' Ye göre ) başladığı satır olarak, <newline> sonlandırılmamış satırı (veya eksik satırı ) yazdıracağını unutmayın .man
-n 1'den başlayarak çıkış hatlarını numaralandırın.
POSIX'in bir çizgiyi nasıl tanımladığını anladığımıza göre , bu davranış belirsiz veya gerçekten uyumlu değildir.
Belirli bir aracın amacını ve uyumluluğunu anlamak, dosyaları bir EOL ile sonlandırmanın ne kadar kritik olduğunu belirlemeye yardımcı olacaktır. C, C ++, Java (JARs, vb.) 'De bazı standartlar geçerlilik için yeni bir satır belirler - JS, HTML, CSS için böyle bir standart yoktur.
Örneğin, wc -l filename
birini kullanmak yerine awk '{x++}END{ print x}' filename
, görevin başarısının bir dosya tarafından tehlikeye atılmadığından emin olun, yazmadığımızı işlemek isteyebiliriz (örneğin, yaptığımız küçültülmüş JS gibi bir üçüncü taraf kütüphanesi curl
) - niyet gerçekten POSIX uyumlu anlamda hatları saymaktı .
Sonuç
JS, HTML ve CSS gibi belirli metin dosyaları için EOF'ta EOL atlamanın olumsuz bir etkisi olacağı çok az gerçek hayat kullanım örneği olacaktır. <newline> 'ın varlığına güvenirsek, takımlarımızın güvenilirliğini yalnızca yazar olduğumuz dosyalarla sınırlandırırız ve kendimizi üçüncü taraf dosyaları tarafından getirilen olası hatalara kadar açarız.
Hikayenin ahlakı: EOF'ta EOL'ye güvenmenin zayıflığı olmayan mühendis araçları.
EOL atlamanın nasıl olumsuz bir etkisi olduğunu inceleyebileceğimiz JS, HTML ve CSS için geçerli oldukları için kullanım durumlarını yayınlamaktan çekinmeyin.
Arasındaki farkla ilişkili olabilir :
Her satır bir satır sonu ile bitiyorsa, bu, örneğin, iki metin dosyasını birleştirmenin ilk çalışmanın son satırını ikincinin ilk satırına dönüştürmesini önler.
Ayrıca, bir düzenleyici dosyanın dosyanın bir satır sonu ile bitip bitmediğini, yerel seçenek 'eol' içine kaydedip kaydetmediğini kontrol edebilir ve dosyayı yazarken bunu kullanabilir.
Birkaç yıl önce (2005), birçok editör (ZDE, Eclipse, Scite, ...) çok takdir edilmeyen son EOL'yi "unuttu" .
Sadece bu da değil, son EOL'yi 'yeni bir satır başlat' olarak yanlış yorumladılar ve aslında başka bir satırı zaten varmış gibi göstermeye başladılar.
Bu, yukarıdaki editörlerden birinde açılmaya kıyasla, vim gibi iyi işlenmiş bir metin düzenleyicisine sahip 'uygun' bir metin dosyasıyla çok görünürdü. Dosyanın gerçek son satırının altında fazladan bir satır görüntüledi. Bunun gibi bir şey görüyorsunuz:
1 first line
2 middle line
3 last line
4
Bazı araçlar bunu bekler. Örneğin, şunu wc
bekler:
$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
wc
gelmez bekliyoruz basitçe "çizgi" nin çoğu insanın sezgisel anlayış yerine bir "çizgi" nin POSIX tanımı içinde çalışmaktadır çok olduğunca bu.
wc -l
yazdırmak içindir 1
, ancak bazı insanlar ikinci vakanın yazdırılması gerektiğini söyleyebilir 2
.
\n
POSIX / UNIX'in yaptığı gibi, bir çizgi ayırıcı yerine bir çizgi sonlandırıcı olarak düşünüyorsanız , ikinci vakanın 2 yazdırmasını beklemek kesinlikle çılgınca olur.
Temel olarak, son EOL EOF'u alamazlarsa dosyaları doğru şekilde işlemeyecek birçok program vardır.
GCC sizi bu konuda uyarıyor çünkü C standardının bir parçası olması bekleniyor. (görünüşte bölüm 5.1.1.2)
Bu, basit terminallerin kullanıldığı ilk günlerden kaynaklanmaktadır. Yeni satır, aktarılan verilerin 'yıkanmasını' tetiklemek için kullanıldı.
Bugün, yeni satır karakterleri artık gerekli değil. Elbette, eğer yeni satır orada değilse birçok uygulamanın hala problemleri var, ancak bu uygulamalarda bir hata olduğunu düşünürdüm.
Bununla birlikte , yeni satırın gerekli olduğu bir metin dosyası biçiminiz varsa , basit veri doğrulamayı çok ucuza alırsınız: dosya sonunda satır sonu olmayan bir satırla bitiyorsa, dosyanın bozuk olduğunu bilirsiniz. Her satır için yalnızca bir bayt ile, yüksek doğrulukta ve neredeyse hiç CPU zamanı olmayan bozuk dosyaları algılayabilirsiniz.
Ayrı bir kullanım örneği: metin dosyanız sürüm kontrollü olduğunda (bu durumda, özellikle diğerleri için de geçerli olmasına rağmen özellikle git altında). Dosyanın sonuna içerik eklenirse, daha önce son satır olan satır yeni satır karakteri içerecek şekilde düzenlenmiş olacaktır. Bu blame
, o satırın en son ne zaman düzenlendiğini öğrenmek için dosyaya girmenin, gerçekten görmek istediğinizden önce değil, metin eklemesini göstereceği anlamına gelir .
\n
) yerine "new lines" ın tespit edilmesi için güncellenmelidir . Sorun çözüldü.
Yukarıdaki pratik nedenlere ek olarak, Unix (Thompson, Ritchie ve diğerleri) veya Multics öncüllerinin yaratıcılarının, hat ayırıcıları kullanmak yerine hat sonlandırıcılarını kullanmanın teorik bir nedeni olduğunu fark etmesi beni şaşırtmaz: sonlandırıcılar, mümkün olan tüm satır dosyalarını kodlayabilirsiniz. Satır ayırıcılarda, sıfır satırlı bir dosya ile tek bir boş satır içeren bir dosya arasında fark yoktur; her ikisi de sıfır karakter içeren bir dosya olarak kodlanır.
Yani nedenleri:
wc -l
yeni satırla bitmezse son bir "satır" saymaz.cat
sadece çalışır ve sorunsuz çalışır. Herhangi bir yoruma gerek kalmadan her dosyanın baytını kopyalar. Ben bir DOS eşdeğer olduğunu sanmıyorum cat
. Kullanıldığında copy a+b c
, son dosya a
satırını ilk dosya satırıyla birleştirirsinizb
.Bunu kendim yıllarca merak ettim. Ama bugün iyi bir nedenle karşılaştım.
Her satırda kaydı olan bir dosya düşünün (ör: CSV dosyası). Ve bilgisayarın dosyanın sonunda kayıtlar yazdığını. Ama aniden çöktü. Gee son çizgiyi tamamladı mı? (hoş bir durum değil)
Ancak her zaman son satırı sonlandırırsak, o zaman bilirdik (sadece son satırın sonlandırılıp sonlandırılmadığını kontrol edin). Aksi takdirde, muhtemelen güvenli olmak için her seferinde son satırı atmamız gerekirdi.
Muhtemelen basitçe bazı ayrıştırma kodunun orada olmasını bekliyordu.
Bunu bir "kural" olarak değerlendireceğime emin değilim ve kesinlikle dinsel olarak bağlı olduğum bir şey değil. En mantıklı kod, metnin (kodlamalar dahil) satır satır (herhangi bir satır sonu seçimi), son satırda yeni satırla veya satır satır olmadan nasıl ayrıştırılacağını bilir.
Gerçekten de - yeni bir çizgiyle bitirirseniz: (teoride) EOL ve EOF arasında boş bir son çizgi var mı? Biri düşünmek için ...
Sonunda yeni satırları olmayan dosyalarla ilgili pratik bir programlama sorunu da var: read
Dahili Bash (diğer read
uygulamalar hakkında bilmiyorum ) beklendiği gibi çalışmıyor:
printf $'foo\nbar' | while read line
do
echo $line
done
Bu sadecefoo
yazdırılır ! Bunun nedeni, read
son satırla karşılaştığında, içindekileri yazar $line
ancak EOF'a ulaştığı için çıkış kodu 1'i döndürür. Bu while
döngüyü kırar , bu yüzden echo $line
parçaya asla ulaşamayız . Bu durumu ele almak istiyorsanız, aşağıdakileri yapmanız gerekir:
while read line || [ -n "${line-}" ]
do
echo $line
done < <(printf $'foo\nbar')
Yani, dosya sonunda boş olmayan bir satır nedeniyle başarısız echo
olursa yapın read
. Doğal olarak, bu durumda çıktıda girdi olmayan bir ekstra yeni satır olacaktır.
(Metin) dosyaları neden bir satırsonu ile bitmelidir?
Pek çok kişi tarafından ifade edildiği gibi, çünkü:
Birçok program iyi davranmaz veya onsuz başarısız olur.
Bir dosyayı iyi işleyen programların bile sonu yoktur '\n'
, aracın işlevselliği kullanıcının beklentilerini karşılamayabilir - bu da bu köşe durumunda net olmayabilir.
Programlar nadiren finali yasaklar'\n'
(hiçbirini bilmiyorum).
Yine de bu bir sonraki soruya yalvarır:
Yeni satır içermeyen metin dosyaları için kod ne yapmalıdır?
En önemlisi - Bir metin dosyasının yeni satırla bittiği varsayılan kod yazmayın . Varsayarsak veri yolsuzluk, hacker saldırıları ve çöker bir biçim potansiyel müşteriler için bir dosya uygundur. Misal:
// Bad code
while (fgets(buf, sizeof buf, instream)) {
// What happens if there is no \n, buf[] is truncated leading to who knows what
buf[strlen(buf) - 1] = '\0'; // attempt to rid trailing \n
...
}
Son takip '\n'
gerekliyse, kullanıcıyı yokluğu ve yapılan işlem konusunda uyarın. IOWs, dosyanın biçimini doğrulayın. Not: Bu, maksimum satır uzunluğu, karakter kodlaması vb. İçin bir sınır içerebilir.
Açıkça tanımlayın, belgeyi, kodun eksik finali ele almasını sağlayın '\n'
.
Mümkün olduğunca, sonu olmayan bir dosya oluşturmayın'\n'
.
Burada çok geç ama ben sadece dosya işleme bir hata ile karşı karşıya ve bu dosyalar boş satırsonu ile bitmedi çünkü geldi. sed
Ve ile metin dosyalarını işliyorduksed
geçersiz json yapısına neden olan ve işlemin geri kalanının başarısız olma durumuna neden olan çıktıdan son satırı çıkarıyorduk.
Tüm yaptığımız şuydu:
Bir örnek dosya var: foo.txt
içinde bazı json
içerikler var.
[{
someProp: value
},
{
someProp: value
}] <-- No newline here
Dosya dul makinede oluşturuldu ve pencere komut dosyaları PowerShell komutlarını kullanarak o dosyayı işliyorlardı. Hepsi iyi.
Aynı dosyayı sed
komut kullanarak işlediğimizdesed 's|value|newValue|g' foo.txt > foo.txt.tmp
Yeni oluşturulan dosya
[{
someProp: value
},
{
someProp: value
ve boom, geçersiz JSON nedeniyle işlemlerin geri kalanında başarısız oldu.
Bu nedenle, dosyanızı boş yeni satırla bitirmek her zaman iyi bir uygulamadır.
Ben her zaman kural son bir satırsonu olmadan bir dosyayı ayrıştırma zor olduğu günlerde geldi izlenimi altındaydı. Yani, satır sonunun EOL karakteri veya EOF tarafından tanımlandığı bir kod yazmanız gerekir. EOL ile biten bir çizgiyi varsaymak daha basitti.
Ancak kuralın satırsonu gerektiren C derleyicilerinden kaynaklandığına inanıyorum. Ve üzerinde sivri out gibi derleyici uyarı “dosya sonunda hiçbir yeni satır” , #include bir yeni satır eklemez.
Dosyanın başka bir işlem tarafından oluşturulmaya devam edildiğini düşünün.
Bununla ilgili olabilir mi? Dosyanın işlenmeye hazır olduğunu belirten bir işaret.
IMHO, kişisel bir tarz ve görüş meselesi.
Eski günlerde, o satırsonu koymadım. Kaydedilen bir karakter, 14.4K modemi sayesinde daha fazla hız anlamına gelir.
Daha sonra, bu yeni satırı, shift + downarrow kullanarak son satırı seçmek daha kolay olacak şekilde koydum.