Phân tích tệp văn bản được phân tách trong bash làm đối số lệnh


10

Tôi có một tệp văn bản được phân chia như vậy:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Mỗi cột này sẽ là một tham số cho một chương trình và tôi muốn chương trình được gọi cho mỗi dòng

Tôi đã hy vọng cho một vòng lặp, đại loại như:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Điều gì sẽ là cách tốt nhất để thực hiện một cái gì đó như thế này trong bash?


Là số lượng các lĩnh vực không đổi?
Joseph R.

@JosephR. đúng vậy, luôn luôn là 3
Trưởng khoa

Câu trả lời:


7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Điều này sẽ làm việc nếu số lượng các lĩnh vực là không đổi. Thay vì echosử dụng lệnh của bạn.


Cảm ơn, tôi chỉ đang thử điều này nhưng nó dường như chỉ hoạt động cho dòng đầu tiên. Ngay sau khi một lệnh thành công, nó sẽ không thử lệnh tiếp theo, nếu thất bại, nó sẽ thử lệnh tiếp theo mặc dù ...
Dean

Làm thế nào để bạn có nghĩa là thành công hay thất bại? Lệnh của bạn làm gì?
coffeMug

Tôi đoán rằng lệnh anh ta đang chạy đang đọc đầu vào tiêu chuẩn trước khi comand "đọc" có thể nhận được.
cắm vào

4

Bạn nên sử dụng a whilevới tích readhợp:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Làm thế nào điều này hoạt động

  • Câu cutlệnh lấy dòng và chia nó trên dấu phân cách được chỉ định bởi -d.
  • --output-delimitertự phân tách cutsẽ sử dụng để hiển thị các trường đã chọn, ở đây chúng tôi chọn một khoảng trắng để chúng tôi có thể đặt các trường khác nhau vào mảng fields.
  • Cuối cùng, chúng tôi muốn tất cả các trường (từ trường 1 đến cuối) và đó là nơi -f1-phát huy tác dụng.
  • Bây giờ bạn có các trường khác nhau được lưu trữ trong biến mảng fields, bạn có thể truy cập bất kỳ trường cụ thể nào bạn muốn với cú pháp ${field[number]}trong đó numberít hơn một số trường thực tế bạn muốn vì lập chỉ mục mảng là không dựa trên Bash.

Ghi chú

  • Điều này sẽ thất bại nếu bất kỳ trường nào của bạn chứa khoảng trắng.

Đối với số lượng trường không đổi

Thay vào đó, bạn có thể làm điều gì đó tương tự như câu trả lời của 1_CR :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

Ở trên, trong khi có vẻ ồn ào hơn, nên hoạt động trong bất kỳ vỏ tuân thủ POSIX nào, không chỉ Bash.


Nó không đọc trong tập tin mà tôi gặp rắc rối, nó chia dòng thành các cột.
Trưởng khoa

@Dean Vâng, xin lỗi. Tôi đã không chú ý. Làm việc trên đó bây giờ.
Joseph R.

@Dean Vui lòng xem câu trả lời cập nhật. Tôi sẽ thêm một lời giải thích trong thời gian ngắn.
Joseph R.

@JosephR., Có thể tránh sử dụng các công cụ bên ngoài để phân tách bằng cách đặt IFSthành một giá trị phù hợp trong lệnh readgọi
iruvar

@ 1_CR Tôi biết, cảm ơn. Tôi vừa mới nhận được điều đó :)
Joseph R.

1

Bạn có thể readphân chia từng dòng thành một mảng ,bằng cách thiết lập IFSphù hợp.

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

Vì vậy, trong ví dụ trên, bạn có thể truy cập từng phần tử mảng bằng chỉ mục của nó, bắt đầu 0.


1

Điều này awkmột lót sẽ làm những gì bạn muốn:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Thay thế echobằng lệnh của bạn và f.txtvới tệp mà bạn muốn lặp qua.

Giải thích ngắn gọn: -F,sẽ đặt ,làm dấu phân cách. cmdxây dựng lệnh và system(cmd)gọi lệnh.


1

gnu sed có thể được sử dụng là tốt.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

Lưu ý việc sử dụng tùy chọn e cho lệnh s

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.