2011-07-08 4 views

Trả lời

5

Vâng, điều này có thể được thực hiện độc đáo trong awk. Thật dễ dàng để có được tất cả các lĩnh vực mà không có bất kỳ hack nghiêm trọng.

(ví dụ này hoạt động trong cả hai The One True Awk và trong gawk.)

{ 
    split($0, a, "\"") 
    $2 = a[2] 
    $3 = $(NF - 1) 
    $4 = $NF 
    print "and the fields are ", $1, "+", $2, "+", $3, "+", $4 
} 
+0

Để định dạng cho một lớp lót: 'cat data.txt | awk 'split ($ 0, a, "\" ") {$ 2 = a [2]} {$ 3 = $ (NF - 1)} {$ 4 = $ NF} {in" và các trường là ", $ 1," + ", $ 2," + ", $ 3," + ", $ 4} '' –

+7

Điều này chỉ hoạt động nếu bạn có một trường được trích dẫn duy nhất, ở vị trí thứ hai và có tổng số 4 trường. –

4

Hãy thử điều này:

$ cat data.txt | awk -F\" '{print $2}' 
I am ABC 
I am not ABC 
+0

tôi nên lưu ý rằng đây không phải là đặc biệt generic - nó chỉ cần thay đổi phân tách trường thành '" và chọn trường thứ hai –

+0

Nhưng nếu tôi muốn sử dụng thông tin trước và sau ... nó sẽ không hoạt động = ( –

+0

@Roy Chan - đúng. Awk không thực sự là đúng công cụ để phân tích các chuỗi được trích dẫn. Chuyển xuống bài đăng thứ ba [tại liên kết Google Cache được định dạng khủng khiếp] (http://webcache.googleusercontent.com/search?q=cache:HA9Ix2yPEasJ:forums11.itrc.hp.com/service/forums/questionanswer.do% 3FthreadId% 3D1028610 + awk + trích dẫn + trường & cd = 1 & hl = vi & ct = clnk & gl = chúng tôi & khách hàng = safari & source = www.google.com) và bạn có thể xem ví dụ dài hơn nhưng có thể hữu ích. –

0

Được rồi, nếu bạn thực sự muốn cả ba lĩnh vực, bạn có thể nhận được chúng, nhưng phải mất rất nhiều đường ống:

$ cat data.txt | awk -F\" '{print $1 "," $2 "," $3}' | awk -F' ,' '{print $1 "," $2}' | awk -F', ' '{print $1 "," $2}' | awk -F, '{print $1 "," $2 "," $3}' 
ABC,I am ABC,35 
DEF,I am not ABC,42 

Bằng đường ống cuối cùng bạn có tất cả ba trường để làm bất cứ điều gì bạn muốn.

+0

Trên thực tế, có 4 lĩnh vực – DigitalRoss

+0

Rất tiếc - Tôi đã bỏ lỡ điều đó trong bản đệ trình ban đầu –

2

Tôi đã kết hợp lại với nhau một hàm chia tách 0 đô la thành một mảng gọi là B. Dấu cách giữa dấu ngoặc kép không hoạt động như dấu tách trường. Hoạt động với bất kỳ số trường nào, kết hợp các trường được trích dẫn và không được trích dẫn. Ở đây đi:

#!/usr/bin/gawk -f 

# Resplit $0 into array B. Spaces between double quotes are not separators. 
# Single quotes not handled. No escaping of double quotes. 
function resplit(  a, l, i, j, b, k, BNF) # all are local variables 
{ 
    l=split($0, a, "\"") 
    BNF=0 
    delete B 
    for (i=1;i<=l;++i) 
    { 
    if (i % 2) 
    { 
     k=split(a[i], b) 
     for (j=1;j<=k;++j) 
     B[++BNF] = b[j] 
    } 
    else 
    { 
     B[++BNF] = "\""a[i]"\"" 
    } 
    } 
} 

{ 
    resplit() 

    for (i=1;i<=length(B);++i) 
    print i ": " B[i] 
} 

Hy vọng điều đó sẽ hữu ích.

2

Câu trả lời hàng đầu cho câu hỏi này chỉ hoạt động đối với các dòng có một trường được trích dẫn. Khi tôi tìm thấy câu hỏi này tôi cần một cái gì đó có thể làm việc cho một số tùy ý của các lĩnh vực được trích dẫn.

Cuối cùng tôi đã đến an answer by Wintermute in another thread và ông đã cung cấp giải pháp tổng quát tốt cho vấn đề này. Tôi vừa sửa đổi nó để xóa dấu ngoặc kép. Lưu ý rằng bạn cần phải gọi awk với -F\" khi chạy chương trình dưới đây.

BEGIN { OFS = "" } { 
    for (i = 1; i <= NF; i += 2) { 
     gsub(/[ \t]+/, ",", $i) 
    } 
    print 
} 

này hoạt động bằng cách quan sát rằng tất cả các yếu tố khác trong mảng sẽ là bên trong dấu ngoặc kép khi bạn tách bởi "của ký tự, và do đó nó sẽ thay thế các khoảng trắng phân chia những người không trong dấu ngoặc kép bằng dấu phẩy.

bạn có thể sau đó dễ dàng chuỗi một ví dụ của awk để làm bất cứ điều gì bạn cần xử lý (chỉ cần sử dụng công tắc lĩnh vực tách một lần nữa, -F,)

Lưu ý rằng điều này có thể phá vỡ nếu trường đầu tiên được trích dẫn -. tôi có không Nếu nó có, mặc dù, nó sẽ được dễ dàng để sửa chữa bằng cách thêm một tuyên bố nếu bắt đầu tại 2 rath er hơn 1 nếu ký tự đầu tiên của dòng là ".

0

Dưới đây là một cái gì đó giống như những gì tôi cuối cùng đã làm việc đó là chung chung hơn cho dự án của tôi. Lưu ý rằng nó không sử dụng awk.

someText="ABC \"I am ABC\" 35 DESC '1 23' testing 456" 
putItemsInLines() { 
    local items="" 
    local firstItem="true" 
    while test $# -gt 0; do 
     if [ "$firstItem" == "true" ]; then 
      items="$1" 
      firstItem="false" 
     else 
      items="$items 
$1" 
     fi 
     shift 
    done 
    echo "$items" 
} 

count=0 
while read -r valueLine; do 
    echo "$count: $valueLine" 
    count=$(($count + 1)) 
done <<< "$(eval putItemsInLines $someText)" 

Những kết quả đầu ra:

0: ABC 
1: I am ABC 
2: 35 
3: DESC 
4: 1 23 
5: testing 
6: 456 
3

Một lựa chọn khác là sử dụng biến FPAT, định nghĩa một biểu thức chính quy mô tả nội dung của từng lĩnh vực.

Lưu kịch bản này AWK như parse.awk:

#!/bin/awk -f 

BEGIN { 
    FPAT = "([^ ]+)|(\"[^\"]+\")" 
} 
{ 
    print $2 
} 

Làm cho nó thực thi với chmod +x ./parse.awk và phân tích tập tin dữ liệu của bạn như ./parse.awk data.txt:

"I am ABC" 
"I am not ABC" 
+0

Cảm ơn bạn đã gửi regex! ;-) Đã lưu tôi ít nhất 20 phút bị thất vọng +1 – jweyrich

+0

Đây phải là câu trả lời được chấp nhận. Nó hoạt động như một sự quyến rũ, cảm ơn. – Nico