2012-07-05 32 views
27

thể trùng lặp:
Looping through the content of a file in Bash?Làm cách nào để lặp qua các dòng trong một tệp bên ngoài có trình bao?

Tôi có một tập tin với một danh sách các tên. Tôi cần phải lặp qua tất cả các tên trong tập tin này từ một tập tin bên ngoài với một kịch bản lệnh shell. Làm thế nào tôi có thể làm điều đó?

Ví dụ file:

scripts/names.txt

alison 
barb 
charlie 
david 

scripts/script.sh

NAMES="" #names from names.txt file 
for NAME in $NAMES; do 
    echo "$NAME" 
done 

Làm thế nào tôi có thể phát nổ file names.txt thành một mảng trong một riêng biệt shell script?

+1

Làm thế nào về một liên kết đến Q & A ban đầu? – bearvarine

Trả lời

54

Một cách sẽ là:

while read NAME 
do 
    echo "$NAME" 
done < names.txt 

EDIT: Lưu ý rằng vòng lặp được thực hiện trong một tiểu shell, vì vậy bất kỳ biến được sửa đổi nào sẽ là cục bộ, ngoại trừ nếu bạn khai báo chúng với declare bên ngoài vòng lặp.

Dennis Williamson là đúng. Rất tiếc, phải sử dụng cấu trúc đường ống quá thường xuyên và bị nhầm lẫn.

+2

Không, vì không có gì được đưa vào trong 'while', không có subshell. Chuyển hướng thành 'done' không tạo ra một vỏ bọc con. –

+0

Bằng cách này, vấn đề (lỗi?) Với đường ống không xảy ra với vỏ korn (nhưng không với pdksh). – cdarke

5

Tôi biết người thuần túy sẽ ghét phương pháp này, nhưng bạn có thể cat tệp.

NAMES=`cat scripts/names.txt` #names from names.txt file 
for NAME in $NAMES; do 
    echo "$NAME" 
done 
+5

Điều này có lợi thế là không gọi một sub-shell, nhưng sẽ xem xét bất kỳ khoảng trống nào trong 'names.txt' như một dấu phân tách. – smocking

+2

"Người thuần túy" cũng sẽ giải thích một cách hữu ích điều này. Có nhiều vấn đề. Xem http://mywiki.wooledge.org/DontReadLinesWithFor – tripleee

6
cat names.txt|while read line; do 
    echo "$line"; 
done 
+4

'trong khi đọc dòng; làm ...; đã thực hiện

13

Bạn sẽ được muốn sử dụng 'đọc' lệnh

while read name 
do 
    echo "$name" 
done < names.txt 

Lưu ý rằng "$ name" được trích dẫn - nếu không, nó sẽ được chia bằng cách sử dụng ký tự trong $IFS làm dấu phân tách. Điều này có thể sẽ không được chú ý nếu bạn chỉ đang lặp lại biến, nhưng nếu tệp của bạn chứa danh sách tên tệp mà bạn muốn sao chép, những tệp đó sẽ bị chia nhỏ theo $IFS nếu biến không được xác định, đó không phải là những gì bạn muốn hoặc mong đợi.

Nếu bạn muốn sử dụng cách tiếp cận Mike Clark (nạp vào một biến hơn là sử dụng đọc), bạn có thể làm điều đó mà không cần dùng cat:

NAMES="$(< scripts/names.txt)" #names from names.txt file 
for NAME in $NAMES; do 
    echo "$NAME" 
done 

Vấn đề ở đây là nó tải toàn bộ tập tin vào $NAMES, khi bạn đọc lại, bạn có thể lấy toàn bộ tệp (nếu được trích dẫn) hoặc tệp được chia nhỏ theo $IFS, nếu không được trích dẫn. Theo mặc định, điều này sẽ cung cấp cho bạn các từ riêng lẻ, chứ không phải các dòng riêng lẻ. Vì vậy, nếu tên "Mary Jane" xuất hiện trên một dòng, bạn sẽ nhận được "Mary" và "Jane" là hai tên riêng biệt. Sử dụng read sẽ làm được việc này ... mặc dù bạn cũng có thể thay đổi giá trị của $IFS

2

Điều này có thể làm việc cho bạn:

cat <<\! >names.txt 
> alison 
> barb 
> charlie 
> david 
> ! 
OIFS=$IFS; IFS=$'\n'; NAMES=($(<names.txt)); IFS=$OIFS 
echo "${NAMES[@]}" 
alison barb charlie david 
echo "${NAMES[0]}" 
alison 
for NAME in "${NAMES[@]}";do echo $NAME;done 
alison 
barb 
charlie 
david 
Các vấn đề liên quan