Извлечь строки между 2 токенами в текстовом файле, используя bash

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

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

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

6 ответов

Решение

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

... | sed -n "/ это токен 1/,/ это токен 2/p" | голова -n-1 | хвост -n+2 

Нет необходимости 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 - ярлык "а"
      • n - читать следующую строку
      • /<!-- this is token 2 -->/q - если это маркер окончания, выйдите
      • p - иначе выведите строку
    • ba - ветвь с меткой "а"
  • } конец, если

Возможно, у 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}

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

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

Не нужно называть могучий 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

За что-нибудь подобное я бы потянулся к 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, $_;
   }
}
sed -n "/TOKEN1/,/TOKEN2/p" <YOUR INPUT FILE> | sed -e '/TOKEN1/d' -e '/TOKEN2/d'
Другие вопросы по тегам