2009-08-07 26 views
14

Tôi có một tệp văn bản có nhiều mục nhập trong đó. Mỗi mục được kết thúc bằng dòng chứa tất cả các dấu hoa thị.Làm cách nào tôi có thể chỉ định kết hợp biểu thức chính quy của tôi với một biến?

Tôi muốn sử dụng lệnh shell để phân tích cú pháp tệp này và gán từng mục nhập cho một biến. Tôi có thể làm cái này như thế nào?

Dưới đây là một ví dụ tập tin đầu vào:

 
*********** 
Field1 
*********** 
Lorem ipsum 
Data to match 
*********** 
More data 
Still more data 
*********** 

Đây là những gì giải pháp của tôi trông như thế cho đến nay:

#!/bin/bash 
for error in `python example.py | sed -n '/.*/,/^\**$/p'` 
do 
    echo -e $error 
    echo -e "\n" 
done 

Tuy nhiên, điều này chỉ gán cho mỗi từ trong văn bản phù hợp đến $ lỗi, chứ không phải hơn cả một khối.

Trả lời

23

Tôi rất ngạc nhiên khi không thấy giải pháp bash gốc tại đây. Có, bash có biểu thức chính quy. Bạn có thể tìm thấy nhiều tài liệu ngẫu nhiên trực tuyến, đặc biệt nếu bạn bao gồm "bash_rematch" trong truy vấn của bạn, hoặc chỉ xem các trang của người đàn ông. Dưới đây là một ví dụ ngớ ngẩn, được lấy từ here và được sửa đổi một chút, in toàn bộ kết quả trùng khớp và mỗi kết quả phù hợp, cho một cụm từ thông dụng.

if [[ $str =~ $regex ]]; then 
    echo "$str matches" 
    echo "matching substring: ${BASH_REMATCH[0]}" 
    i=1 
    n=${#BASH_REMATCH[*]} 
    while [[ $i -lt $n ]] 
    do 
     echo " capture[$i]: ${BASH_REMATCH[$i]}" 
     let i++ 
    done 
else 
    echo "$str does not match" 
fi 

Các bit quan trọng là các thử nghiệm mở rộng [[ ... ]] sử dụng regex so sánh nó =~ cửa hàng toàn bộ trận đấu trong ${BASH_REMATCH[0]} và các trận đấu bị bắt trong ${BASH_REMATCH[i]}.

+1

Thật vậy, nó sẽ rất tuyệt nếu có một hướng dẫn dứt khoát để bash biểu thức thông thường, nhưng như @ Jefromi nói, nó chỉ là một loạt các ngẫu nhiên. – g33kz0r

+0

@Noah: Từ trang người đàn ông: "chuỗi bên phải của toán tử được coi là một biểu thức chính quy mở rộng và phù hợp cho phù hợp (như trong regex (3)." Vì vậy, đó là POSIX mở rộng regex, có? Điều đó có vẻ ... khá – Cascabel

+0

Đó là tất cả tốt và tốt, Jefromi.Nhưng nó không phải là diveintobashregex.org – g33kz0r

0

tùy thuộc vào những gì bạn muốn làm gì với các biến

awk ' 
f && /\*/{print "variable:"s;f=0} 
/\*/{ f=1 ;s="";next} 
f{ 
    s=s" "$0 
}' file 

đầu ra:

# ./test.sh 
variable: Field1 
variable: Lorem ipsum Data to match 
variable: More data Still more data 

trên chỉ in chúng ra. nếu bạn muốn, lưu trữ trong mảng để sử dụng sau này ... ví dụ array [++ d] = s

1

Nếu bạn muốn làm điều đó trong Bash, bạn có thể làm một cái gì đó như sau. Nó sử dụng globbing thay vì regexps (Tùy chọn vỏ extglob cho phép mô hình kết hợp mở rộng, vì vậy chúng tôi có thể phù hợp với một dòng gồm duy nhất của dấu hoa thị.)

#!/bin/bash 
shopt -s extglob 
entry="" 
while read line 
do 
    case $line in 
     +(\*)) 
      # do something with $entry here 
      entry="" 
      ;; 
     *) 
      entry="$entry$line 
" 
      ;; 
    esac 
done 
0

hồ sơ tách trong (ba) sh không phải là quá dễ dàng, nhưng có thể được thực hiện bằng cách sử dụng IFS để chia thành các ký tự đơn (chỉ cần đặt IFS = '*' trước vòng lặp for, nhưng điều này tạo ra nhiều bản ghi trống và có vấn đề nếu bất kỳ bản ghi nào chứa '*'). Giải pháp hiển nhiên là sử dụng perl hoặc awk và sử dụng RS để chia nhỏ các bản ghi của bạn, vì những công cụ này cung cấp cơ chế tốt hơn cho việc tách bản ghi. Một giải pháp lai là sử dụng perl để làm việc tách bản ghi, và có perl gọi hàm bash của bạn với bản ghi mà bạn muốn. Ví dụ:

#!/bin/bash 

foo() { 
    echo record start: 
    echo "[email protected]" 
    echo record end 
} 
export -f foo 

perl -e "$/='********'; while(<>){chomp;system(\"foo '\$_'\")}" << 'EOF' 
this is a 2-line 
record 
******** 
the 2nd record 
is 3 lines 
long 
******** 
a 3rd * record 
EOF 

Điều này cho phép đầu ra sau đây:

 
record start: 
this is a 2-line 
record 

record end 
record start: 

the 2nd record 
is 3 lines 
long 

record end 
record start: 

a 3rd * record 

record end 
+0

Lưu ý rằng tập lệnh được cung cấp ở đây hầu như chắc chắn yêu cầu/bin/sh phải được bash. –

1

Hãy thử đặt dấu ngoặc kép quanh lệnh.

#!/bin/bash 
for error in "`python example.py | sed -n '/.*/,/^\**$/p'`" 
do 
    echo -e $error 
    echo -e "\n" 
done 
Các vấn đề liên quan