Подтвердить что ты не робот

Bash, grep между двумя строками с указанной строкой

Пример:

a43
test1
abc
cvb
bnm
test2
kfo

Мне нужны все строки между test1 и test2. В этом случае нормальный grep не работает. Есть ли у вас какие-либо предложения?

4b9b3361

Ответ 1

Печать от test1 до test2 (test2 триггерные линии)

awk '/test1/{f=1} /test2/{f=0;print} f'
awk '/test1/{f=1} f; /test2/{f=0}' 
awk '/test1/,/test2/'

test1
abc
cvb
bnm
test2

Печатает данные между test1 to test2 (исключая строки запуска)

awk '/test1/{f=1;next} /test2/{f=0} f' 
awk '/test2/{f=0} f; /test1/{f=1}' 

abc
cvb
bnm

Ответ 2

Вы можете использовать sed:

sed -n '/test1/,/test2/p' filename

Чтобы исключить строки, содержащие test1 и test2, скажем:

sed -n '/test1/,/test2/{/test1/b;/test2/b;p}' filename

Ответ 3

Если вы можете использовать grep:

grep -A100000 test1 file.txt | grep -B100000 test2 > new.txt

grep -A, а затем число получает строки после строки соответствия, а grep -B получает строки перед соответствующей строкой. Число, 100000 в этом случае, должно быть достаточно большим, чтобы включать все строки до и после.

Если вы не хотите включать test1 и test2, вы можете впоследствии удалить их с помощью grep -v, который печатает все, кроме соответствующих строк:

egrep -v "test1|test2" new.txt > newer.txt

или все в одной строке:

grep -A100000 test1 file.txt | grep -B100000 test2 | egrep -v "test1|test2" > new.txt 

Ответ 4

Да, нормальный grep этого не сделает. Но grep с параметром -P выполнит эту работу.

$ grep -ozP '(?s)test1\n\K.*?(?=\ntest2)' file
abc
cvb
bnm

\K отбрасывает ранее согласованные символы от печати в финале, а положительный lookahead (?=\ntest2) утверждает, что за совпадением должен следовать символ \n новой строки, а затем строка test2.

Ответ 5

Следующий script завершает этот процесс. Подробнее fooobar.com/questions/28804/...

get_text.sh

function show_help()
{
  HELP=$(doMain $0 HELP)
  echo "$HELP"
  exit;
}

function doMain()
{
  if [ "$1" == "help" ]
  then
    show_help
  fi
  if [ -z "$1" ]
  then
    show_help
  fi
  if [ -z "$2" ]
  then
    show_help
  fi

  FILENAME=$1
  if [ ! -f $FILENAME ]; then
      echo "File not found: $FILENAME"
      exit;
  fi

  if [ -z "$3" ]
  then
    START_TAG=$2_START
    END_TAG=$2_END
  else
    START_TAG=$2
    END_TAG=$3
  fi

  CMD="cat $FILENAME | awk '/$START_TAG/{f=1;next} /$END_TAG/{f=0} f'"
  eval $CMD
}

function help_txt()
{
HELP_START
  get_text.sh: extracts lines in a file between two tags

  usage: FILENAME {TAG_PREFIX|START_TAG} {END_TAG}

  examples:
    get_text.sh 1.txt AA     => extracts lines in file 1.txt between AA_START and AA_END
    get_text.sh 1.txt AA BB  => extracts lines in file 1.txt between AA and BB
HELP_END
}

doMain $*

Ответ 6

Вы тоже можете сделать что-то подобное. Допустим, вы этот файл test.txt с контентом:

a43
test1
abc
cvb
bnm
test2
kfo

Вы можете сделать

cat test.txt | grep -A10 test1 | grep -B10 test2

где -A<n> должно вывести строки n после вашего совпадения в файле, а -B<n> - дать вам строки n перед совпадением. Вы просто должны убедиться, что n > number of expected lines between test1 and test2. Или вы можете дать ему достаточно большой, чтобы достичь EOF.

Результат:

test1
abc
cvb
bnm
test2

Ответ 7

Ответ от PratPor выше:

cat test.txt | grep -A10 test1 | grep -B10 test2

классно.. но если вы не знаете длину файла:

cat test.txt | grep -A1000 test1 | grep -B1000 test2

Не детерминированный, но не слишком плохой. Кто-нибудь лучше (более детерминированный)?

Ответ 8

awk '/test1/,/test2/' filename.txt > outputFile.txt