Bir dosyanın hatları üzerinde nasıl döngü?


61

Diyelim ki bu dosya var:

hello
world
hello world

Bu program

#!/bin/bash

for i in $(cat $1); do
    echo "tester: $i"
done

çıktılar

tester: hello
tester: world
tester: hello
tester: world

forHer satırdaki yinelemenin tek tek boşlukları görmezden gelmesini isterim , yani son iki satırın yerini alması gerekir.

tester: hello world

Tırnak kullanma for i in "$(cat $1)";sonuçlanır iseferde tüm dosyayı tahsis edilmektedirler. Neyi değiştirmeliyim?

Yanıtlar:


69

İle forve IFS :

#!/bin/bash

IFS=$'\n'       # make newlines the only separator
set -f          # disable globbing
for i in $(cat < "$1"); do
  echo "tester: $i"
done

Bununla birlikte, IFS-boşluk karakterli yeni satır olarak boş satırları atlayacağını , dizilerinin 1 olarak sayıldığını ve önde gelen ve sondakilerin dikkate alınmadığını unutmayın. İle zshve ksh93(değil bash), sen olarak değiştirebilirsiniz IFS=$'\n\n'ancak, yeni satır özel olarak tedavi edilmesi için değil, tüm dikkat sondaki yeni satır karakterleri (böylece boş satırları sondaki içerir) daima komut ikamesi yoluyla kaldırılacaktır.

Veya ileread (artık cat):

#!/bin/bash

while IFS= read -r line; do
  echo "tester: $line"
done < "$1"

Orada boş satırlar korunur, ancak eğer yeni satır karakteriyle düzgün bir şekilde sınırlandırılmamışsa son satırı atlayacağını unutmayın.


5
teşekkürler, birinin <bütün bir döngüye girebileceğini bilmiyordum . Şimdi her ne kadar mantıklı gelse de gördüm
Tobias Kienzler

1
IFS \ read -r line' in second example. Is really IFS = `gerekli görüyorum ? IMHO söyleyecek kadar:while read -r line; do echo "tester: $line"; done < "$1"
Grzegorz Wierzowiecki

4
@ GrzegorzWierzowiecki IFS=, önde gelen ve sondaki boşlukların sıyrılmasını kapatır. Bkz olarak while IFS= read.., neden IFS hiçbir etkisi var mı?
Gilles 'SO- kötülük olmayı bırak'

0

Buna değecekse, bunu çok sık yapmam gerekiyor ve kullanım şeklini asla hatırlayamıyorum while IFS= read..., bu yüzden bash profilimde şu işlevi tanımladım:

# iterate the line of a file and call input function
iterlines() {
    (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; }
    local File=$1
    local Func=$2
    n=$(cat "$File" | wc -l)
    for (( i=1; i<=n; i++ )); do
        "$Func" "$(sed "${i}q;d" "$File")"
    done
}

Bu işlev ilk önce dosyadaki satır sayısını belirler, ardından sedsatırdan sonra satır ayıklamak için kullanır ve her satırı, verilen herhangi bir işleve tek bir dize argümanı olarak iletir. Sanırım bu büyük dosyalarda gerçekten verimsiz olabilir, ancak bu benim için şu ana kadar bir sorun olmamıştır (elbette bu hoşgeldin nasıl geliştirileceği üzerine öneriler).

Kullanımı oldukça tatlı IMO:

>> cat example.txt # note the use of spaces, whitespace, etc.
a/path

This is a sentence.
"wi\th quotes"
$End
>> iterlines example.txt echo # preserves quotes, $ and whitespace
a/path

This is a sentence.
"wi\th quotes"
$End
>> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string
1
1 
1
1
1
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.