La commande grep
imprimera une ligne lorsque celle-ci contient une chaîne correspondant à une expression, ce qui n’est pas pratique pour rechercher un contenu spécifié.
Par exemple, j'ai des fichiers de vocabulaire avec le formatage
**Word**
1. Definition:
2. Usage
3. Others
Je voudrais récupérer tous les mots pour faire une liste de mots dans les fichiers
grep '\*\*[^*]*\*\*'
Renvoie la majeure partie du contenu.
Comment utiliser grep
pour ne capturer que le Word
?
Avec awk
manière:
awk -F'*\\*' 'NF>2{print $2}' infile
exemple de test d'entrée:
*wrd*
*woooord
**WRD
Word**
woooooooooood*
**Word**
le résultat:
Word
Comme pour Word, utilisez Perl regex (-P
):
grep -oP '^\s*\*\*\K[^*]+(?=\*\*)' file
Word
Comme ça pour les mots:
grep -oP '^\s*\d+\.\s*\K\w+' file
Definition
Usage
Others
Il existe plusieurs outils disponibles pour extraire Word. Voici une version implémentée dans sed:
sed '/^\*\*/!d' <your_file
Cette commande correspondra à chaque ligne de votre fichier commençant par **
et l’imprimera. Les autres lignes seront supprimées de la sortie. Si vous souhaitez également supprimer les étoiles, vous pouvez étendre la commande à ceci:
sed '/^\*\*/!d;s/\*//g' <your_file
En outre, cette commande supprimera tous les caractères *
de la ligne avant son impression.
C'est l'une de ces questions où il est utile de disposer d'un fichier d'entrée de test et d'exemples de sortie souhaitée.
Voici un fichier d'entrée de test que j'ai copié depuis Internet et modifié pour envelopper les mots de recherche dans les paires **
:
$ cat ~/Downloads/wordlist.txt
**Schadenfreude**
This is a German Word, although used in English too, which is used to mean ‘malicious enjoyment of the misfortunes of others’. It comes from the joining of the words schaden meaning ‘harm’ and freude meaning ‘joy’.
**Waldeinsamkeit**
Ever found yourself wandering alone through a forest and wanting to express the emotion brought about by that wander? Look no further! In German, Waldeinsamkeit means ‘woodland solitude’.
**L’esprit de l’escalier**
We all know the feeling of walking away from an argument and instantly thinking of the ideal comeback, or leaving a conversation and remembering the perfect contribution to a no-longer relevant subject. In French, l’esprit de l’escalier is the term used to refer to that irritating feeling. It literally translates as ‘the spirit of the staircase’, more commonly known as ‘staircase wit’. It comes from the idea of thinking of a response as you’re leaving somebody’s house, via their staircase.
**Schlimazel**
The Mr Men series of books by Roger Hargreaves is a staple of many a British child’s bookshelves, and there is a Word which could have been created for the character Mr Bump. Like Mr Bump, a Schlimazel is ‘a consistently unlucky, accident-prone person, a born loser’. It is a Yiddish Word, coming from the Middle High German Word slim meaning ‘crooked’ and the Hebrew mazzāl meaning ‘luck’.
**Depaysement**
Ever go on holiday, only to experience a strange sensation of disorientation at the change of scenery? Dépaysement is a French Word which refers to that feeling of disorientation that specifically arises when you are not in your home country.
**Duende**
This Spanish term implies something magical or enchanting. It originally referred to a supernatural being or spirit similar to an imp or pixie (and is occasionally borrowed in that sense into English with reference to Spanish and Latin American folklore). Now, it has adapted to refer to the spirit of art or the power that a song or piece of art has to deeply move a person.
**Torschlusspanik**
Are you getting older? Scared of being left behind or ‘left on the shelf’? This British idiom has its own Word in German: Torschlusspanik, which literally translates as ‘panic at the shutting of a gate’, is used frequently in a general sense meaning ‘last –minute panic’, of the type you might experience before a deadline.
*Do*Not*Return*these four star lines
*Word***
***Word*
Word**
grep
Utiliser grep
c'est assez simple d'obtenir une liste Word:
$ grep -E -o '\*\*[^*]{,20}\*\*' ~/Downloads/wordlist.txt
**Schadenfreude**
**Waldeinsamkeit**
**L’esprit de l’escalier**
**Schlimazel**
**Depaysement**
**Duende**
**Torschlusspanik**
Si vous souhaitez supprimer le **
contenant les mots, ajoutez un tuyau à sed
:
$ grep -E -o '\*\*[^*]{,20}\*\*' ~/Downloads/wordlist.txt | sed 's/*//g'
Schadenfreude
Waldeinsamkeit
L’esprit de l’escalier
Schlimazel
Depaysement
Duende
Torschlusspanik
Si vous souhaitez enregistrer vos sorties grep
et sed
, utilisez la commande de redirection de fichier >
:
$ grep -E -o '\*\*[^*]{,20}\*\*' ~/Downloads/wordlist.txt | sed 's/*//g' > ~/Downloads/wordlist-index.txt
$ cat ~/Downloads/wordlist-index.txt
Schadenfreude
Waldeinsamkeit
L’esprit de l’escalier
Schlimazel
Depaysement
Duende
Torschlusspanik
Notez la réponse originale postée hier enrichie du nouveau message d’aujourd’hui de muru sur un Q & A séparé: tilisez le quantificateur spécifié dans grep pour récupérer du vocabulaire satisfait
Si cela ne vous dérange pas d'utiliser des outils supplémentaires, une solution très simple serait de post-filtrer la sortie grep
avec tr
pour supprimer toutes les occurrences du caractère *
:
grep -x '\*\*[^*]*\*\*' | tr -d '*'
Je vous recommande également d'utiliser le drapeau -x
de GNU grep comme ci-dessus pour ne faire correspondre que des lignes entières afin de ne pas prendre accidentellement **Word**
apparaissant entouré d'un autre texte sur la même ligne. Cela peut également accélérer le processus de filtrage car il peut maintenant éliminer de nombreuses correspondances potentielles très tôt.
sed
alternativeVous pouvez également tirer parti du drapeau p
de sed pour faire correspondre, remplacer et imprimer en une seule commande:
sed -nre 's/^\*\*([^*]*)\*\*$/\1/p'
Votre cas particulier consiste à extraire du texte entre deux modèles sur une ligne/chaîne. Cela a été couvert dans la question de 2012 Comment utiliser sed/grep pour extraire du texte entre deux mots? . En particulier, comme anishsane est mentionné, vous pouvez utiliser des modèles d’avant-garde et de regard sur le passé avec le drapeau Perl-regex -P
. Dans votre cas particulier, la solution serait
grep -o -P '(?<=\*\*).*(?=\*\*)' input.txt
Cependant, comme ghoti est mentionné, -P
est spécifique à GNU grep
. Gardez cela à l’esprit si vous portez vos scripts/commandes entre différents systèmes * nix.
Au lieu d'essayer d'utiliser Perl regex, utilisons simplement Perl lui-même:
$ Perl -a -F\\*\\* -lane 'print $F[1] if /\*\*/' input.txt
Word
Cela a deux avantages. Premièrement, il spécifie le délimiteur pour "champs", ce qui signifie que nous pouvons traiter des éléments individuels séparés par **
. Deuxièmement, syntaxiquement, cela est juste un peu moins déroutant que le modèle d'anticipation/régression.
Bien sûr, il existe d'autres moyens de le faire, et l'un d'eux est Python. Le script Python 2.7 serait:
#!/usr/bin/env python
from __future__ import print_function
import sys
for f in sys.argv[1:]:
with open(f) as fd:
for line in fd:
if line.startswith('**'):
print(line.split('*')[2])
Vous pouvez également en faire un one-liner et tirer parti de la redirection stdin:
python -c 'import re,sys; print "\n".join([ l.split("**")[1] for l in sys.stdin if "**" in l ])' < input.txt
D'autres qui préfèrent regex, voudront peut-être utiliser le module re
.
python -c 'import re,sys; print "\n".join([ re.split("\*\*",l)[1] for l in sys.stdin if "**" in l ])' < input.txt