Làm thế nào để lặp qua các dòng của một tập tin?


61

Nói rằng tôi có tập tin này:

hello
world
hello world

Chương trình này

#!/bin/bash

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

đầu ra

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

Tôi muốn có forlần lặp qua từng dòng riêng lẻ bỏ qua các khoảng trắng, tức là hai dòng cuối cùng sẽ được thay thế bằng

tester: hello world

Sử dụng dấu ngoặc kép dẫn for i in "$(cat $1)";đến iviệc được gán toàn bộ tệp cùng một lúc. Tôi nên thay đổi cái gì?

Câu trả lời:


69

Với forIFS :

#!/bin/bash

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

Tuy nhiên, xin lưu ý rằng nó sẽ bỏ qua các dòng trống vì dòng mới là ký tự khoảng trắng IFS, các chuỗi của nó được tính là 1 và các dòng đầu và cuối được bỏ qua. Với zshksh93(không bash), bạn có thể thay đổi nó để IFS=$'\n\n'cho xuống dòng không được đối xử đặc biệt, tuy nhiên lưu ý rằng tất cả các đuôi ký tự xuống dòng (để bao gồm trailing dòng trống) sẽ luôn luôn được gỡ bỏ bởi sự thay thế lệnh.

Hoặc vớiread (không hơn cat):

#!/bin/bash

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

Ở đó, các dòng trống được giữ nguyên, nhưng lưu ý rằng nó sẽ bỏ qua dòng cuối cùng nếu nó không được phân định chính xác bởi một ký tự dòng mới.


5
cảm ơn, tôi không biết người ta có thể <vào một vòng lặp. Mặc dù nó hoàn toàn có ý nghĩa bây giờ tôi đã thấy nó
Tobias Kienzler

1
Tôi thấy IFS \ read -r line' in second example. Is really IFS = `cần thiết? IMHO đủ để nói:while read -r line; do echo "tester: $line"; done < "$1"
Grzegorz Wierzowiecki

4
@GrzegorzWierzowiecki IFS=tắt tước khoảng trắng hàng đầu và dấu. Xem trong while IFS= read.., tại sao IFS không có hiệu lực?
Gilles 'SO- ngừng trở nên xấu xa'

0

Đối với những gì đáng giá, tôi cần phải làm điều đó khá thường xuyên và không bao giờ có thể nhớ chính xác cách sử dụng while IFS= read..., vì vậy tôi đã xác định hàm sau trong hồ sơ bash của mình:

# 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
}

Hàm này trước tiên xác định số lượng dòng trong tệp, sau đó sử dụng sedđể trích xuất dòng sau dòng và chuyển từng dòng dưới dạng một đối số chuỗi cho bất kỳ hàm đã cho. Tôi cho rằng điều này có thể thực sự không hiệu quả với các tệp lớn, nhưng điều đó không phải là vấn đề đối với tôi cho đến nay (tất nhiên là đề xuất về cách cải thiện sự chào đón này).

Cách sử dụng khá ngọt ngào 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.