Yeni satırla bitmeyebilecek satır yönelimli bir dosyayı okuyun


11

/tmp/urlFileHer satırın bir url temsil ettiği adlı bir dosya var . Aşağıdaki gibi dosyadan okumaya çalışıyorum:

cat "/tmp/urlFile" | while read url
do
    echo $url
done

Son satır yeni satır karakteri ile bitmezse, bu satır okunmaz. Nedenini merak ediyordum?

Yeni bir satırla bitip bitmemelerine bakılmaksızın tüm satırları okumak mümkün müdür?



2
Hah @ Stéphane TBD'yi seviyorum ;-).
Stephen Kitt

2
Kayıp sondaki yeni satırı eklemenin başka bir yolu; awk 1 /tmp/urlFile.. yaniawk 1 /tmp/urlFile | while ...
muru

muru, bu diğerlerinden daha iyi bir cevap.
Joker

1
Neden okunmadığını sorduğunuzdan : stackoverflow.com/a/729795/1968
Konrad Rudolph

Yanıtlar:


13

Yapacaksın:

while IFS= read -r url || [ -n "$url" ]; do
  printf '%s\n' "$url"
done < url.list

(etkin bir şekilde, bu döngü son satırdaki (olmayan) eksik yeni satırı geri ekler).

Ayrıca bakınız:


Teşekkürler. Bağlantılı makaleleri okudum ve belki de bir şeyleri özlüyorum, neden "bu döngü son satırdaki (eksik) son satırsonunu geri ekliyor?"
Tim

1
@Tim Stephane'nin anlamı, printfburadaki tüm çağrıların sahip olduğu için çıkıştaki eksik yeni satırı geri eklemesidir \n.
Sergiy Kolodyazhnyy

6

Bu kısmen şu şekilde çözülmüş görünüyor readarray -t:

readarray -t urls "/tmp/urlFile"
for url in "${urls[@]}"; do
    printf '%s\n' "$url"
done

Bununla birlikte, bu makul boyutlu dosyalar için işe yarasa da, bu çözümün çok büyük dosyalarla yeni bir potansiyel sorun oluşturduğunu unutmayın - önce dosyayı yinelenmesi gereken bir diziye okur. Çok büyük dosyalar için bu hem zaman hem de bellek tüketen bir durum olabilir, bu da potansiyel olarak hata noktasına neden olabilir.


Teşekkürler. Hangi kısmı çözer, hangisini çözmez?
Tim

Sondaki yeni satırın olmamasıyla sorunu çözer, ancak çok büyük dosyalar ile potansiyel yeni bir sorun oluşturur, çünkü önce dosyayı tekrarlanması gereken bir diziye okur.
DopeGhoti

1
@DopeGhoti Bu iyi bilgi - doğrudan cevaba eklemenizi önerebilir miyim?
RJHunter

Bu cevap çok değiştirildi.
DopeGhoti

5

Tarafından tanımı , bir metin dosyası satır bir dizisinden oluşur. Bir satır , yeni satır karakteri ile biter. Bu nedenle, bir metin dosyası boş değilse yeni satır karakteri ile biter.

readBuiltin yalnızca metin dosyalarını okumak içindir. Bir metin dosyasını geçirmiyorsunuz, bu yüzden sorunsuz bir şekilde çalışmasını umut edemezsiniz. Kabuk tüm satırları okur - atladığı şey son satırdan sonraki ekstra karakterlerdir.

Son satırında eksik olabilecek potansiyel olarak hatalı biçimlendirilmiş bir giriş dosyanız varsa, emin olmak için bir satırsonu ekleyebilirsiniz.

{ cat "/tmp/urlFile"; echo; } | 

Metin dosyaları olması gereken ancak son satırsonu eksik olan dosyalar genellikle Windows editörleri tarafından üretilir. Bu genellikle Unix'in LF'sinin aksine CR LF olan Windows satır sonlarıyla birlikte gider. CR karakterleri nadiren hiçbir yerde kullanışlıdır ve her durumda URL'lerde görünemez, bu yüzden bunları kaldırmalısınız.

{ <"/tmp/urlFile" tr -d '\r'; echo; } | 

Giriş dosyasının iyi biçimlendirilmesi ve bir satırsonu ile bitmesi durumunda, echofazladan bir boş satır ekler. URL'ler boş olamayacağından, boş satırları yok saymanız yeterlidir.

Ayrıca readsatırları basit bir şekilde okumaz. Bir URL için muhtemelen istenen önde gelen ve sondaki boşlukları yok sayar. Bir çizginin sonundaki ters eğik çizgiyi bir kaçış karakteri olarak ele alır ve bir sonraki çizginin ilk eksi ters eğik çizgi yeni dizisi ile birleştirilmesine neden olur, bu kesinlikle arzu edilmez. Bu nedenle -rseçeneği geçmelisiniz read. readDoğru şey olmak çok ama çok nadirdir read -r.

{ <"/tmp/urlFile" tr -d '\r'; echo; } | while read -r url
do
  if [ -z "$url" ]; then continue; fi
  
done

3

Eh, readyeni bir satırdan önce sona dosya-karşılıyorsa bir falsy değer döndürür, ama öyle olsa bile, yine de okumak değerini atar. Böylece, son çağrıların readboş bir satırdan başka bir şey döndürüp döndürmediğini kontrol edebilir ve normal olarak işleyebiliriz. Bu nedenle, döngüden yalnızca readfalse döndürdükten ve satır boş olduktan sonra çıkın :

#!/bin/sh
while IFS= read -r line || [ "$line" ]; do 
    echo "line: $line"
done

$ printf 'foo\nbar' | sh ./read.sh 
line: foo
line: bar
$ printf 'foo\nbar\n' | sh ./read.sh 
line: foo
line: bar

1

Başka bir yol şöyle olurdu:

Okuma satır sonu yerine dosya sonuna ulaştığında, verileri okur ve değişkenlere atar, ancak sıfırdan farklı bir durumla çıkar. Döngünüz oluşturulmuşsa "okurken; bir şeyler yapın; bitti

Bu nedenle, doğrudan okuma çıkış durumunu test etmek yerine, bir bayrağı test edin ve okuma komutunun döngü gövdesinden bu bayrağı ayarlamasını sağlayın. Bu şekilde, okuma çıkış durumundan bağımsız olarak, tüm döngü gövdesi çalışır, çünkü okuma, döngüdeki komutların tüm listelerinden sadece biriydi, döngünün çalışıp çalışmayacağı konusunda belirleyici bir faktör değildi.

DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY 
done < /tmp/urlFile

Buradan atıfta bulunuldu .


1
cat "/ tmp / urlFile" | url'yi okurken
yapmak
    echo $ url
tamam

Bu Yararsız bir Kullanımdırcat .

İronik bir şekilde, buradaki catişlemi gerçekten kullanışlı bir şeyle değiştirebilirsiniz : POSIX sistemlerinin eksik yeni satırı eklemek ve dosyayı uygun bir POSIX metin dosyasına dönüştürmek için sahip olduğu bir araç.

sed -e '$ a \' "/ tmp / urlFile" | okurken -r url
yapmak
    printf "% s \ n" "$ {url}"
tamam

daha fazla okuma


1
Giriş yeni satır karakteriyle bitmediğinde sed davranışı POSIX tarafından belirtilmez; LINE_MAX'tan daha büyük satırlar olduğunda da read, bu durumlarda davranışı belirtilir.
Stéphane Chazelas
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.