2011-01-31 29 views
17

tôi có một tập tin văn bản mà trông như thế này:dòng Extract giữa 2 thẻ trong một file văn bản sử dụng bash

random useless text 
<!-- this is token 1 --> 
para1 
para2 
para3 
<!-- this is token 2 --> 
random useless text again 

tôi muốn trích xuất văn bản ở giữa các thẻ (không bao gồm các thẻ tất nhiên). Tôi đã thử sử dụng ## và %% để trích xuất dữ liệu ở giữa nhưng nó không hoạt động. Tôi nghĩ rằng nó không có nghĩa là để thao tác các tập tin văn bản lớn như vậy. Bất kỳ đề xuất làm thế nào tôi có thể làm điều đó? có lẽ là awk hay sed?

Trả lời

22

Bạn có thể giải nén nó, bao gồm các thẻ với sed. Sau đó sử dụng đầu và đuôi để cắt các thẻ.

... | sed -n "/this is token 1/,/this is token 2/p" | head -n-1 | tail -n+2

+0

dường như trên hệ điều hành MacOS sử dụng một dòng âm tính cho kết quả đầu trong 'sở chính: số dòng bất hợp pháp - -1' – balupton

0

Đối với bất cứ điều gì như thế này, tôi sẽ liên hệ với Perl, với sự kết hợp của (trong số những người khác) sedawk khả năng. Một cái gì đó tương tự (hãy cẩn thận - chưa được kiểm tra):

my $recording = 0; 
my @results =(); 
while (<STDIN>) { 
    chomp; 
    if (/token 1/) { 
     $recording = 1; 
    } 
    else if (/token 2/) { 
     $recording = 0; 
    } 
    else if ($recording) { 
     push @results, $_; 
    } 
} 
0

Hãy thử như sau:

sed -n '/<!-- this is token 1 -->/,/<!-- this is token 2 -->/p' your_input_file 
     | egrep -v '<!-- this is token . -->' 
1

Có lẽ sed và awk có các giải pháp thanh lịch hơn, nhưng tôi có cách tiếp cận "người nghèo" với grep, cắt, đầu và đuôi.

#!/bin/bash 

dataFile="/path/to/some/data.txt" 
startToken="token 1" 
stopToken="token 2" 

startTokenLine=$(grep -n "${startToken}" "${dataFile}" | cut -f 1 -d':') 
stopTokenLine=$(grep -n "${stopToken}" "${dataFile}" | cut -f 1 -d':') 

let stopTokenLine=stopTokenLine-1 
let tailLines=stopTokenLine-startTokenLine 

head -n ${stopTokenLine} ${dataFile} | tail -n ${tailLines} 
34

Không cần headtail hoặc grep hay để đọc các tập tin nhiều lần:

sed -n '/<!-- this is token 1 -->/{:a;n;/<!-- this is token 2 -->/b;p;ba}' inputfile 

Giải thích:

  • -n - không làm một in ngầm
  • /<!-- this is token 1 -->/{ - nếu tìm thấy điểm đánh dấu bắt đầu, thì
    • :a - nhãn "a"
      • n - đọc dòng tiếp theo
      • /<!-- this is token 2 -->/q - nếu đó là dấu hiệu kết thúc, bỏ
      • p - nếu không, hãy in dòng
    • ba - chi nhánh để gắn nhãn "a"
  • } kết thúc nếu
+0

Tôi thích giải pháp của bạn. – armandino

+1

Tôi cũng thích! Sed khi làm bất cứ điều gì nhiều hơn thay thế đơn giản thực sự đòi hỏi một lời giải thích. Vì vậy, 1 cho bạn thưa bạn! – Deleted

+0

Trong kịch bản sed của bạn, bạn đã sử dụng 'b' để thoát khỏi vòng lặp, nhưng trong các giải thích của bạn, bạn đã sử dụng' q' (tôi nhận thấy điều này khi sử dụng lệnh của bạn, 'q' dường như làm sed thoát ngay lập tức trong khi' b' sẽ thoát vòng lặp nhưng tiếp tục tìm kiếm dấu hiệu 'token 1' tiếp theo –

0

không cần phải gọi hùng mạnh sed/awk/perl. Bạn có thể làm điều đó "bash-only":

#!/bin/bash 
STARTFLAG="false" 
while read LINE; do 
    if [ "$STARTFLAG" == "true" ]; then 
      if [ "$LINE" == '<!-- this is token 2 -->' ];then 
        exit 
      else 
        echo "$LINE" 
      fi 
    elif [ "$LINE" == '<!-- this is token 1 -->' ]; then 
      STARTFLAG="true" 
      continue 
    fi 
done < t.txt 

Kind coi

realex

Các vấn đề liên quan