web-dev-qa-db-fra.com

Bash, grep entre deux lignes avec la chaîne spécifiée

Exemple:

a43
test1
abc
cvb
bnm
test2
kfo

J'ai besoin de toutes les lignes entre test1 et test2. Grep normal ne fonctionne pas dans ce cas. Avez-vous des propositions?

53
user3162968

Imprimer depuis test1 à test2 (Lignes de déclenchement incluses)

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

Imprime les données entre test1 à test2 (Lignes de déclenchement exclues)

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

Vous pouvez utiliser sed:

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

Pour exclure les lignes contenant test1 et test2, dire:

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

Si vous ne pouvez utiliser que grep:

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

grep -A puis un nombre obtient les lignes après la chaîne correspondante et grep -B obtient les lignes avant la chaîne correspondante. Le nombre, 100 000 dans ce cas, doit être assez grand pour inclure toutes les lignes avant et après.

Si vous ne souhaitez pas inclure test1 et test2, vous pouvez ensuite les supprimer en grep -v, qui affiche tout sauf la ou les lignes correspondantes:

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

ou tout en une ligne:

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

Oui, grep normal ne le fera pas. Mais grep avec -P paramètre fera ce travail.

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

\K _ élimine les caractères précédemment correspondants de l’impression lors de la finale et l’anticipation positive (?=\ntest2) affirme que la correspondance doit être suivie d'un \n caractère de nouvelle ligne, puis test2 chaîne.

6
Avinash Raj

La réponse de PratPor ci-dessus:

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

c'est cool .. mais si vous ne connaissez pas la longueur du fichier:

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

Pas déterministe, mais pas trop mal. Quelqu'un a mieux (plus déterministe)?

0
Tweeks

Vous pouvez faire quelque chose comme ça aussi. Disons que vous ce fichier test.txt avec contenu:

a43
test1
abc
cvb
bnm
test2
kfo

Tu peux faire

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

-A<n> est de vous obtenir n lignes après votre correspondance dans le fichier et -B<n> est de vous donner n lignes avant le match. Vous devez juste vous assurer que n > number of expected lines between test1 and test2. Ou vous pouvez le donner assez grand pour atteindre EOF.

Résultat:

test1
abc
cvb
bnm
test2
0
pratpor

Le script suivant termine ce processus. Plus de détails dans cet article similaire de 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