web-dev-qa-db-ja.com

bash、指定された文字列を持つ2行間のgrep

例:

a43
test1
abc
cvb
bnm
test2
kfo

Test1とtest2の間のすべての行が必要です。この場合、通常のgrepは機能しません。何か提案はありますか?

53
user3162968

test1から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からtest2までのデータを印刷します(トリガー行は除外されます)

awk '/test1/{f=1;next} /test2/{f=0} f' 
awk '/test2/{f=0} f; /test1/{f=1}' 
abc
cvb
bnm
51
Jotne

sedを使用できます:

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

test1およびtest2を含む行を除外するには、次のように言います。

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

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

またはすべてを1行で:

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

はい、通常のgrepはこれを行いません。ただし、-Pパラメーターを指定したgrepがこのジョブを実行します。

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

\Kは、前に一致した文字を最後の印刷から破棄し、肯定的な先読み(?=\ntest2)は、一致の後に\n改行文字、次にtest2文字列が続く必要があることを表明します。

6
Avinash Raj

上記のPratPorによる答え:

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

クールですが、ファイルの長さがわからない場合:

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

確定的ではありませんが、それほど悪くはありません。誰もがより良い(より決定論的)ですか?

0
Tweeks

このようなこともできます。このファイル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
0
pratpor

次のスクリプトは、このプロセスをまとめています。詳細 この似たようなStackOverflowの投稿

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 $*
0
Brad Parks