Làm thế nào để đọc các dòng khác nhau của một tập tin cho các biến khác nhau?


14

Tôi muốn đọc các dòng khác nhau của một tệp văn bản cho các biến khác nhau. Ví dụ

input.txt:

line1 foo foobar bar
line2 bar
line3 foo
line4 foobar bar

Tôi muốn kết quả này phải được lưu trữ trong các biến var1, var2, var3var4như vậy

var1=line1 foo foobar bar
var2=line2 bar

và như thế.

Ai đó có thể xin vui lòng cho tôi biết làm thế nào nó được thực hiện. Tôi đã cố gắng sử dụng evaltrong một vòng lặp for. Nó dường như không hoạt động.



3
Đây là một cách tiếp cận xấu. Kể từ khi về cơ bản là lý do duy nhất để biến thiết lập là để làm điều gì đó với họ, và kể từ khi có một số lượng lớn các công cụ đặc biệt được thiết kế để làm việc với tất cả các dòng văn bản trong một tập tin (awk, sed, grep, cut, et. Al.), sẽ tốt hơn nhiều nếu chỉ làm những gì bạn cần làm. Không micromanage trong một kịch bản shell; phối hợp các công cụ để hoàn thành công việc
tự đại diện

Câu trả lời:


20

Bạn sẽ làm:

unset -v line1 line2
{ IFS= read -r line1 && IFS= read -r line2; } < input.txt

Hoặc là:

{ line1=$(line) && line2=$(line); } < input.txt

(ít hiệu quả hơn vì linehiếm khi được tích hợp sẵn và hầu hết các shell cần rẽ nhánh để thực hiện thay thế lệnh. linecũng không còn là lệnh tiêu chuẩn).

Để sử dụng một vòng lặp:

unset -v line1 line2 line3
for var in line1 line2 line3; do
  IFS= read -r "$var" || break
done < input.txt

Hoặc để tự động xác định tên của các biến là line<++n>:

n=1; while IFS= read -r "line$n"; do
  n=$((n + 1))
done < input.txt

Lưu ý rằng bashhỗ trợ các biến mảng và tích hợp readarrayđể đọc các dòng thành một mảng:

readarray -t line < input.txt

Lưu ý rằng tuy nhiên trái với hầu hết các tiện ích khác, bashchỉ số mảng bắt đầu từ 0 không 1 (thừa hưởng từ ksh), do đó dòng đầu tiên sẽ được trong ${line[0]}, không ${line[1]}(mặc dù như @Costas đã cho thấy , bạn có thể làm readarray(aka mapfile) bắt đầu viết các giá trị tại indice 1 ( bashmảng cũng trái với hầu hết các shell khác là mảng thưa thớt ) với -O 1).

Xem thêm: Hiểu "IFS = read -r line"?


12

Tôi đề nghị sử dụng mảng cho các tác vụ đó

mapfile -t -O 1 var <input.txt

vì vậy bạn sẽ có từng dòng trong ${var[1]}, ${var[2]}v.v.


Điều này một lót hoạt động rất tốt. Giải quyết vấn đề cho tôi.
Matt Zabojnik

0

Đây không phải là những gì bạn yêu cầu, nhưng nó có thể đáp ứng nhu cầu của bạn. Bạn có thể tuần tự hóa dữ liệu với Awk. Lưu ý rằng điều này sẽ phá vỡ nếu $ 1 của bạn không phải là tên biến hợp lệ:

awk '
function quote(str,   d, m, x, y, z) {
  d = "\47"; m = split(str, x, d)
  for (y in x) z = z d x[y] (y < m ? d "\\" d : d)
  return z
}
{
  print $1 "=" quote($0)
}
' input.txt > /tmp/input.sh
. /tmp/input.sh

Kết quả:

$ echo "$line1"
line1 foo foobar bar

Đây là mã nghiêm trọng kỳ lạ! Có vẻ như bạn đang sử dụng awk để biến toàn bộ tệp đầu vào thành tập lệnh bash mà sau đó bạn nguồn. Tôi có một ý tưởng mơ hồ về những gì quote () đang làm. Tên biến mô tả nhiều hơn sẽ giúp. Bạn có thể giải thích mọi thứ nhiều hơn một chút?
Joe
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.