J'essaie de sortir une chaîne qui contient tout ce qui se trouve entre deux mots d'une chaîne:
contribution:
"Here is a String"
sortie:
"is a"
En utilisant:
sed -n '/Here/,/String/p'
inclut les points finaux, mais je ne veux pas les inclure.
sed -e 's/Here\(.*\)String/\1/'
GNU grep peut également prendre en charge l’anticipation positive et négative. Dans votre cas, la commande serait la suivante:
echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'
S'il existe plusieurs occurrences de Here
et string
, vous pouvez choisir de faire correspondre le premier Here
et le dernier string
ou de les faire correspondre individuellement. En termes de regex, il est appelé match glouton (premier cas) ou match non glouton (deuxième cas)
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*(?=string)' # Greedy match
is a string, and Here is another
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*?(?=string)' # Non-greedy match (Notice the '?' after '*' in .*)
is a
is another
La réponse acceptée ne supprime pas le texte qui pourrait être avant Here
ou après String
. Cette volonté:
sed -e 's/.*Here\(.*\)String.*/\1/'
La principale différence est l'ajout de .*
immédiatement avant Here
et après String
.
Vous pouvez effacer les chaînes dans Bash seul:
$ foo="Here is a String"
$ foo=${foo##*Here }
$ echo "$foo"
is a String
$ foo=${foo%% String*}
$ 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 String" | grep -Po '(?<=(Here )).*(?= String)'
is a
À travers GNU awk,
$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
is a
grep avec -P
(Perl-regexp) prend en charge \K
, ce qui permet de supprimer les caractères précédemment correspondants. Dans notre cas, la chaîne précédemment mise en correspondance était Here
et a donc été supprimée de la sortie finale.
$ echo "Here is a string" | grep -oP 'Here\K.*(?=string)'
is a
$ echo "Here is a string" | grep -oP 'Here\K(?:(?!string).)*'
is a
Si vous voulez que la sortie soit is a
, alors vous pouvez essayer ce qui suit,
$ echo "Here is a string" | grep -oP 'Here\s*\K.*(?=\s+string)'
is a
$ echo "Here is a string" | grep -oP 'Here\s*\K(?:(?!\s+string).)*'
is a
Si vous avez un fichier long avec plusieurs occurrences multilignes, il est utile d’imprimer d’abord les lignes numériques:
cat -n file | sed -n '/Here/,/String/p'
Cela pourrait fonctionner pour vous (GNU sed):
sed '/Here/!d;s//&\n/;s/.*\n//;:a;/String/bb;$!{n;ba};:b;s//\n&/;P;D' file
Ceci présente chaque représentation de texte entre deux marqueurs (dans ce cas Here
et String
) sur une nouvelle ligne et conserve les nouvelles lignes dans le texte.
Toutes les solutions ci-dessus ont des défauts dans lesquels la dernière chaîne de recherche est répétée ailleurs dans la chaîne. Je trouvais préférable 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 string"
str_str "$mystr" "this " " string"
Vous pouvez utiliser \1
(voir http://www.grymoire.com/Unix/Sed.html#uh-4 ):
echo "Hello is a String" | sed 's/Hello\(.*\)String/\1/g'
Le contenu entre crochets sera stocké sous le nom \1
.
Pour comprendre la commande sed
, nous devons la construire étape par étape.
Voici votre texte original
user@linux:~$ echo "Here is a String"
Here is a String
user@linux:~$
Essayons de supprimer Here
avec l'option s
ubstition dans sed
.
user@linux:~$ echo "Here is a String" | sed 's/Here //'
is a String
user@linux:~$
À ce stade, je pense que vous pourrez supprimer String
ainsi
user@linux:~$ echo "Here is a String" | sed 's/String//'
Here is a
user@linux:~$
Mais ce n'est pas votre sortie souhaitée.
Pour combiner deux commandes sed, utilisez l’option -e
user@linux:~$ echo "Here is a String" | sed -e 's/Here //' -e 's/String//'
is a
user@linux:~$
J'espère que cela t'aides
Problème. Mes messages Claws Mail stockés sont emballé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 Efflux Essential Amino Acids from Lysosomes and Use Protein as
a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway
identified [Lysosomal amino acid transporter SLC38A9 signals arginine
sufficiency to mTORC1]]
Message-ID: <[email protected]>
Par A2 dans ce fil de discussion, 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é l’essai de nombreuses variantes (.+?; /s; ...
), je n’arrivais pas à les faire fonctionner:
grep -o -P '(?<=Subject: ).*(?=link)' corpus/01
grep -o -P '(?<=Subject: ).*(?=therapeutic)' corpus/01
etc.
Solution 1.
Per Extrait le 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 Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient 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) avec sed?
sed ':a;N;$!ba;s/\n/ /g' corpus/01
remplacera les nouvelles lignes par un espace.
En chaînant cela avec A2 dans Comment utiliser sed/grep pour extraire du texte entre deux mots? , on obtient:
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 Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]
Cette variante supprime les doubles espaces:
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 Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]