Comment utiliser sed / grep pour extraire du texte entre deux mots?

J’essaie de sortir une chaîne qui contient tout entre deux mots d’une chaîne:

consortingbution:

"Here is a Ssortingng" 

sortie:

 "is a" 

En utilisant:

 sed -n '/Here/,/Ssortingng/p' 

inclut les points d’extrémité, mais je ne veux pas les inclure.

 sed -e 's/Here\(.*\)Ssortingng/\1/' 

Grep simple peut également prendre en charge le look & ahead positif et négatif: pour votre cas, la commande serait:

  echo "Here is a ssortingng" | grep -o -P '(?< =Here).*(?=string)' 

Vous pouvez supprimer des chaînes dans Bash seul:

 $ foo="Here is a Ssortingng" $ foo=${foo##*Here } $ echo "$foo" is a Ssortingng $ foo=${foo%% Ssortingng*} $ echo "$foo" is a $ 

Et si vous avez un GNU grep qui inclut PCRE , vous pouvez utiliser une assertion de largeur nulle:

 $ echo "Here is a Ssortingng" | grep -Po '(?< =(Here )).*(?= String)' is a 

La réponse acceptée ne supprime pas le texte qui pourrait être avant Here ou After Ssortingng . Cette volonté:

 sed -e 's/.*Here\(.*\)Ssortingng.*/\1/' 

La principale différence est l’ajout de .* Immédiatement avant Here et After Ssortingng .

Grâce à GNU awk,

 $ echo "Here is a ssortingng" | awk -v FS="(Here|ssortingng)" '{print $2}' is a 

grep avec le paramètre -P ( perl-regexp ) supporte \K , ce qui permet de supprimer les caractères précédemment associés. Dans notre cas, la chaîne précédemment appariée était Here , elle a donc été supprimée de la sortie finale.

 $ echo "Here is a ssortingng" | grep -oP 'Here\K.*(?=ssortingng)' is a $ echo "Here is a ssortingng" | grep -oP 'Here\K(?:(?!ssortingng).)*' is a 

Si vous voulez que la sortie soit is a vous pouvez essayer le ci-dessous,

 $ echo "Here is a ssortingng" | grep -oP 'Here\s*\K.*(?=\s+ssortingng)' is a $ echo "Here is a ssortingng" | grep -oP 'Here\s*\K(?:(?!\s+ssortingng).)*' is a 

Si vous avez un fichier long avec de nombreuses occurrences de plusieurs lignes, il est utile d’imprimer d’abord des lignes de chiffres:

 cat -n file | sed -n '/Here/,/Ssortingng/p' 

Cela pourrait fonctionner pour vous (GNU sed):

 sed '/Here/!d;s//&\n/;s/.*\n//;:a;/Ssortingng/bb;$!{n;ba};:b;s//\n&/;P;D' file 

Cela présente chaque représentation de texte entre deux marqueurs ( Here , Here et Here ) sur une nouvelle ligne et conserve les nouvelles lignes dans le texte.

Toutes les solutions ci-dessus présentent des insuffisances lorsque la dernière chaîne de recherche est répétée ailleurs dans la chaîne. J’ai trouvé mieux d’écrire une fonction bash.

  function str_str { local str str="${1#*${2}}" str="${str%%$3*}" echo -n "$str" } # test it ... mystr="this is a ssortingng" str_str "$mystr" "this " " ssortingng" 

Vous pouvez utiliser \1 (voir http://www.grymoire.com/Unix/Sed.html#uh-4 ):

 echo "Hello is a Ssortingng" | sed 's/Hello\(.*\)Ssortingng/\1/g' 

Le contenu qui se trouve entre les crochets sera stocké comme \1 .

Problème. Mes messages Claws Mail stockés sont encapsulés comme suit et j’essaie d’extraire les lignes Objet:

 Subject: [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efstream Essential Amino Acids from Lysosomes and Use Protein as a Nusortingent] [Re: Nusortingent sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]] Message-ID: <20171019190902.18741771@VictoriasJourney.com> 

Par A2 dans ce fil, Comment utiliser sed / grep pour extraire du texte entre deux mots? la première expression, ci-dessous, “fonctionne” tant que le texte correspondant ne contient pas de nouvelle ligne:

 grep -o -P '(?< =Subject: ).*(?=molecular)' corpus/01 [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key 

Cependant, malgré de nombreuses variantes ( .+?; /s; ... ), je ne pouvais pas les faire fonctionner:

 grep -o -P '(?< =Subject: ).*(?=link)' corpus/01 grep -o -P '(?<=Subject: ).*(?=therapeutic)' corpus/01 etc. 

Solution 1.

Per Extrait du texte entre deux chaînes sur des lignes différentes

 sed -n '/Subject: /{:a;N;/Message-ID:/!ba; s/\n/ /g; s/\s\s*/ /g; s/.*Subject: \|Message-ID:.*//g;p}' corpus/01 

qui donne

 [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efstream Essential Amino Acids from Lysosomes and Use Protein as a Nusortingent] [Re: Nusortingent sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]] 

Solution 2. *

Per Comment puis-je remplacer une nouvelle ligne (\ n) par sed?

 sed ':a;N;$!ba;s/\n/ /g' corpus/01 

remplacera les nouvelles lignes par un espace.

En enchaînant avec A2 dans Comment utiliser sed / grep pour extraire du texte entre deux mots? , on a:

 sed ':a;N;$!ba;s/\n/ /g' corpus/01 | grep -o -P '(?< =Subject: ).*(?=Message-ID:)' 

qui donne

 [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efstream Essential Amino Acids from Lysosomes and Use Protein as a Nusortingent] [Re: Nusortingent sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]] 

Cette variante supprime les espaces doubles:

 sed ':a;N;$!ba;s/\n/ /g; s/\s\s*/ /g' corpus/01 | grep -o -P '(?< =Subject: ).*(?=Message-ID:)' 

donnant

 [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efstream Essential Amino Acids from Lysosomes and Use Protein as a Nusortingent] [Re: Nusortingent sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]