Lấy các giá trị của một phần của tệp


7

Tôi có một tập tin cấu hình theo định dạng sau.

<Title>
 [part1]
  A.File = a
  A.Val = val1
  B.File = a
  B.Val = val1
 [part2]
  A.File = a1
  A.Val = val2 
  B.File = a
  B.Val = val1

Tôi chỉ muốn trích xuất các giá trị từ phần đầu tiên.

 #!/bin/sh 
getCalibDate()
{
 file="/path/of/config/file"
 value=`cat ${file} | grep Val | cut -d'=' -f2`
    for v in $value
    do
            echo $v
    done
}
getCalibDate

Kịch bản trên sẽ trả về tất cả các giá trị. Làm thế nào tôi có thể nhận được các giá trị từ chỉ phần đầu tiên (phần 1)?


5
Lưu ý đó cat file | grep foolà vô nghĩa. Nó được gọi là "sử dụng mèo vô dụng" . Bạn luôn có thể làm grep foo filethay thế.
terdon

Nói ${file}thay vì chỉ đơn giản $filelà đôi khi hữu ích, nhưng nó hữu ích hơn nhiều để có được thói quen nói "$file". Nói ${file}sẽ không bảo vệ bạn khỏi có không gian hoặc ký tự đại diện $file.
G-Man nói 'Phục hồi Monica'

Câu trả lời:


8

Nếu bạn chỉ có 4 dòng sau khi [part1]bạn có thể sử dụng -A4tùy chọn với grep:

cat ${file} | grep -A4 "part1" | cut -d'=' -f2`

Đối với trường hợp chung (hơn 4 dòng sau [part1]), hãy sử dụng sedđể lấy văn bản giữa hai phần:

cat ${file} | sed -n "/part1/,/part2/p" | head -n-1

headlà để xóa bổ sung part2vào cuối

Như terdon nói rằng bạn không phải sử dụng cat, thay vào đó bạn có thể thực hiện các thao tác sau:

grep -A4 "part1" ${file} | cut -d'=' -f2`

HOẶC LÀ:

sed -n "/part1/,/part2/p" ${file} | head -n-1

4

Bạn cần sử dụng một công cụ tinh vi hơn để phân tích tệp. Ví dụ awk:

#!/bin/sh 

getCalibDate()
{
 file="${1}"
 value=$(awk  '/\[part/{a++}(a<2 && /Val/){print $NF}' ${file})

    for v in $value
    do
            echo $v
    done
}

getCalibDate ${1}

Ở đây, biến ađược tăng lên mỗi khi một dòng khớp [part. Sau đó, trường cuối cùng ( $NF) được in khi một dòng khớp Valnhưng chỉ khi anhỏ hơn 2, chỉ khi chúng ta ở phần 1.


awkchỉ là một công cụ tuyệt vời
Nidal

2
@ Mạng vâng vâng. Đó là một ngôn ngữ lập trình đầy đủ, có một số chương trình rất phức tạp được viết bằng awk. Một trong những thuật toán dự đoán gen đầu tiên chẳng hạn.
terdon

Câu hỏi cho biết cut -d'=' -f2, mang lại trường giới hạn thứ hai =. Câu trả lời của bạn mang lại trường giới hạn không gian cuối cùng. Chúng giống nhau cho dữ liệu mẫu trong câu hỏi, nhưng đó là dữ liệu mẫu . Tôi tự hỏi dữ liệu thực sự trông như thế nào.
G-Man nói 'Phục hồi Monica'

@ G-Man đúng. Ban đầu tôi đã viết awk -F= '{print $2}'điều tương tự nhưng tôi cảm thấy nó $NFđơn giản hơn trong trường hợp này.
terdon

@terdon: Dự đoán gen ?? Đó là một chút ... awk
user541686

2

và sử dụng cái này:

sed -n -e '/\[part1\]/,/\[part2\]/p' FILE |sed -e '1d;$d'| awk -F "=" '{print $2}'

ĐẦU RA là:

 a
 val1
 a
 val1

2

Để có được toàn bộ dòng từ phần đầu tiên:

awk '$1 ~ /^\[/ {n++;next} n==1'

Để chỉ in phía bên phải của đầu tiên =:

awk '$1 ~ /^\[/ {n++;next} n==1 {sub(/^[^=]*=[[:blank:]]*/,""); print}'

2

Có một số câu trả lời hay ở đây, nhưng tôi chỉ thấy một câu kết hợp Valmột phần của vấn đề và không rõ liệu điều đó có đúng hay không. Tôi đồng ý rằng đó awklà một công cụ tuyệt vời, nhưng nó không cần thiết ở đây; Tôi tin rằng sedlệnh này :

sed -n '/\[part1\]/,/\[part2\]/s/.*Val.*=//p' "$file"

có lẽ làm những gì mong muốn. Giống như các sed -e '/\[part1\]/,/\[part2\]/p'giải pháp khác ( NetworkerBabyy ), đây là khả năng thích ứng tầm thường để chọn bất kỳ phần nào. (Bạn làm gì, tất nhiên, cần phải biết tên của nó, nếu bạn chỉ biết số thứ tự của nó, bạn có thể thích nghi với câu trả lời terdon của hoặc câu trả lời glenn jackman của , cả hai đều đếm phần chứ không phải là tìm kiếm một tên cụ thể.) Nếu bạn không biết tên của phần sau, bạn có thể làm

sed -n '/ \ [part42 \] /, / \ [part / s' '$ file "

ví dụ.

Câu hỏi meta duy nhất của tôi liên quan đến cut -d'=' -f2một phần của câu hỏi. Nếu một dòng đầu vào mà chúng tôi trích xuất dữ liệu chứa nhiều =ký tự sau Val(nghĩa là giá trị trường chứa =ký tự), vd

Einstein.Val = E=mc^2

sau đó cutlệnh trên sẽ chỉ trích xuất văn bản giữa = giá trị thứ nhất và thứ hai (nghĩa là giá trị trường, tối đa (nhưng không bao gồm) đầu tiên =), ví dụ :  E. Các sedlệnh tôi đã trình bày ở trên sẽ trích xuất chỉ các văn bản sau khi cuối cùng = (ví dụ mc^2). Để có được mọi thứ sau lần đầu tiên =(ví dụ E=mc^2:), hãy sử dụng

sed -n '/\[part1\]/,/\[part2\]/s/.*Val[^=]*=//p' "$file"

Để bắt chước hành vi của cut(ví dụ  E:), hãy sử dụng

sed -n '/\[part1\]/,/\[part2\]/s/.*Val[^=]*=\([^=]*\).*/\1/p' "$file"

Lưu ý rằng phương pháp của tôi giả định rằng dữ liệu nhìn ít nhất giống như minh họa trong câu hỏi; tức là, ít nhất một cái =xuất hiện ở đâu đó bên phải Valchuỗi. Theo đó, tất cả các giải pháp của tôi sẽ bỏ qua đầu vào như

Girl.Name = Valerie
Valerie Bertinelli

ngay cả khi nó rơi vào giữa [part1][part2].


Điều cuối cùng của bạn không bắt chước hành vi cắt. Nếu cutchia tách bằng và chỉ in trường thứ hai của dòng và - như tôi nghĩ bạn đang cố gắng đề xuất - có nhiều hơn các trường khớp thì bạn cũ sẽ xử lý vấn đề của ba trường khớp cuối cùng . Và đây là cách lệnh của bạn không bắt chước cut.
mikeerv

@mikeerv: Hả? Gì?
G-Man nói 'Phục hồi Monica'

đúng như những gì tôi nói - Nó không bắt chước vì bạn làm s/.*... Làm điều đó có nghĩa là nó sẽ chỉ xảy ra lần cuối cùng có thể xảy ra Val[^=]*=\([^=]*\).*/\1. Có vẻ như bạn đã làm việc đó rất nhiều chỉ vì điều đó, có thể.
mikeerv

@mikeerv: Chỉ là những gì tôi [sic] đã nói? Nghiêm túc? Có thể có nhiều lĩnh vực phù hợp hơn so với các lĩnh vực cũ của bạn, đó là một bước tiến lên từ sự vô nghĩa - Tôi hy vọng có một lỗi đánh máy trong đó, nhưng tôi không thể đoán được ý của bạn. “Xử lý các vấn đề của cuối cùng ba lĩnh vực phù hợp với” chỉ là một chút dễ hiểu hơn. Bạn có nghĩa là lệnh của tôi sẽ thất bại cho dòng có chứa “ Val…=…Val…=”? Nếu vậy, tôi đoán bạn đúng; Tôi đã không xem xét trường hợp đó. Nhưng không có trong bình luận đầu tiên của bạn cho thấy đó là những gì bạn đang nói, và bình luận thứ hai của bạn vẫn chưa rõ ràng.
G-Man nói 'Phục hồi Monica'

@mikeerv: Hãy nhớ rằng, tôi đã nói, Lưu ý rằng cách tiếp cận của tôi giả định rằng dữ liệu nhìn chung ít nhất giống như minh họa trong câu hỏi. Nếu bạn sẽ tuyên bố rằng giải pháp của tôi thất bại ở đầu vào trông hoàn toàn khác với minh họa trong câu hỏi, thì nó sẽ cho bạn ít nhất là đưa ra một ví dụ về đầu vào mà lệnh của tôi thất bại.
G-Man nói 'Phục hồi Monica'

0
sed -n '/part2/q;s/[^=]*=//p' \
<<\DATA
<Title>
 [part1]
  A.File = a
  A.Val = val1
  B.File = a
  B.Val = val1
 [part2]
  A.File = a1
  A.Val = val2
  B.File = a
  B.Val = val1
DATA

ĐẦU RA

 a
 val1
 a
 val1

Điều đó sẽ làm các trick. Nó sẽ ngay lập tức quit file đầu vào trong lần đầu tiên nó gặp chuỗi part2 ở bất cứ đâu trong đầu vào. Điều này có nghĩa là nó thậm chí không bao giờ cố đọc qua các phần của tệp bạn không muốn - điều này sẽ làm cho nó rất hiệu quả.

Việc -nvô hiệu hóa tự động in để sedchỉ in những gì nó chắc chắn được nói với print. Lần duy nhất chắc chắn được yêu cầu in là khi nó có thể xóa thành công một chuỗi 0 hoặc nhiều ký tự không phải =và một ký tự là một =.

Nếu bạn muốn in toàn bộ dòng phù hợp thay vào đó bạn có thể làm:

sed -n '/part2/q;/=/p'
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.