Извлечь строки между 2 токенами в текстовом файле, используя bash - PullRequest
20 голосов
/ 01 февраля 2011

У меня есть текстовый файл, который выглядит следующим образом:

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

Я хочу извлечь текст между токенами (исключая токены, конечно).Я пытался использовать ## и %% для извлечения данных между ними, но это не сработало.Я думаю, что он не предназначен для манипулирования такими большими текстовыми файлами.Любые предложения, как я могу это сделать?может быть, awk или sed?

Ответы [ 6 ]

39 голосов
/ 01 февраля 2011

Нет необходимости в head и tail или grep или для чтения файла несколько раз:

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

Объяснение:

  • -n - донне делайте неявной печати
  • /<!-- this is token 1 -->/{ - если начальный маркер найден, тогда
    • :a - метка "a"
      • n - читатьследующая строка
      • /<!-- this is token 2 -->/q - если это конечный маркер, закройте
      • p - в противном случае выведите строку
    • ba -переход к метке "a"
  • } конец, если
25 голосов
/ 01 февраля 2011

Вы можете извлечь его, включая токены с помощью sed. Затем используйте голову и хвост, чтобы снять жетоны.

... | sed -n "/this is token 1/,/this is token 2/p" | head -n-1 | tail -n+2
1 голос
/ 20 февраля 2017

не нужно называть могучий sed / awk / perl. Вы можете сделать это только для bash:

#!/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

С уважением

Realex

1 голос
/ 01 февраля 2011

Может быть, у sed и awk есть более элегантные решения, но у меня есть подход "бедняги" с grep, cut, head и tail.

#!/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}
1 голос
/ 01 февраля 2011

Попробуйте следующее:

sed -n '/<!-- this is token 1 -->/,/<!-- this is token 2 -->/p' your_input_file
        | egrep -v '<!-- this is token . -->'
0 голосов
/ 01 февраля 2011

За что-то подобное я бы достиг Perl с его комбинацией (среди прочих) sed и awk возможностей.Что-то вроде (будьте осторожны - не проверено):

my $recording = 0;
my @results = ();
while (<STDIN>) {
   chomp;
   if (/token 1/) {
      $recording = 1;
   }
   else if (/token 2/) {
      $recording = 0;
   }
   else if ($recording) {
      push @results, $_;
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...