grep --before-context 5
montre 5 lignes avant le match.
Je veux tout montrer avant le match.
Cela grep --before-context 99999999
fonctionnerait, mais ce n'est pas très ... professionnel.
Comment afficher tout le fichier jusqu'au match?
grep --before-context 5
montre 5 lignes avant le match.
Je veux tout montrer avant le match.
Cela grep --before-context 99999999
fonctionnerait, mais ce n'est pas très ... professionnel.
Comment afficher tout le fichier jusqu'au match?
Réponses:
Sed est mieux pour ça.
Il suffit de faire:
sed '/PATTERN/q' FILE
Cela fonctionne comme ceci:
Pour chaque ligne, on regarde si elle correspond /PATTERN
:
C'est la solution la plus efficace, car dès qu'elle voit PATTERN
, elle se ferme. Sans cela q
, sed continuerait à lire le reste du fichier et ne ferait rien avec. Pour les gros fichiers, cela peut faire la différence.
Cette astuce peut également être utilisée pour émuler head
:
sed 10q FILE
sed '/PATTERN/Q' FILE
ignorera la ligne correspondante. Q
est une extension GNU, donc cela ne fonctionnera pas avec sed.
sed
peut remplacer la plupart des fonctionnalités de grep.
sed -n '1,/<pattern>/ p' <file>
Cela signifie que l’impression commence à la première ligne jusqu’à ce que le motif corresponde.
Quelques exemples de gamme
sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2
imprimer jusqu'au match inclus:
awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename
imprimer jusqu'à MAIS sans inclure le match:
awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename
Q
est cool mais spécifique au gnou, sed -n '/pattern/!p;//q'
serait plus portable.
!
cela p
s'applique aux lignes ne correspondant paspattern
, mais //q
cela
//
signifie "expression régulière précédente" (je pensais que cela signifiait "faire correspondre la chaîne vide"). Je pense qu'une version plus courte de la même solution est sed -n '/pattern/q;p
:?
Les grep
méthodes GNU pures suivantes ne sont pas efficaces.
Recherchez tout jusqu'à la première instance de la chaîne " foo " dans la barre de fichiers , en utilisant trois grep
mots:
grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar
Correspondant à la dernière instance de " foo ":
grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar
Remarque: les détails sur le dernier grep
peuvent être trouvés dans: Regex (grep) pour la recherche multiligne nécessaire .
grep
s (+ pcre) quand il s’agit simplement de lancer une seule sed
invocation: sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'
??
sed
code semble avoir sa propre réponse, ou pourrait être ajouté à l'un des autres. Re 7 grep
s: Parce qu'il n'y avait pas de grep
réponse ... (plus, la réponse aide montre pourquoi pas.)
Ajoutant à la réponse de Mikel ci-dessus ...
Pour imprimer toutes les lignes jusqu'à, mais sans inclure , la première ligne FILE
contenant PATTERN
, essayez:
sed '/.*PATTERN.*/{s///;q;}' FILE
Cela correspond à la ligne entière contenant le motif, le remplace par une ligne vierge, puis se ferme sans traiter le reste du fichier.
Post-script:
Le moyen le plus simple et le plus clair que je pouvais imaginer pour empêcher l’impression d’une nouvelle ligne supplémentaire à la fin (sans faire appel à un autre outil) était de lancer à nouveau sed et de supprimer la nouvelle ligne finale:
sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'
... et puisque nous supprimons cette ligne de toute façon, nos travaux précédents sont redondants et nous pouvons simplifier pour:
sed '/PATTERN/q' FILE | sed '$d'
sed
invocation.
tcsh
et en bash
alias, je devais m'assurer que je avait une solution monoligne relativement concise qui fonctionnait à la fois en version standard et GNU sed
(pour la portabilité); toutes les exigences que votre contribution peut très bien avoir satisfait. En tant que personne qui utilise sed
très rarement, mon exigence la plus importante concernait quelque chose que je pouvais comprendre rapidement lorsque je souhaitais la modifier ou la réutiliser facilement dans des années.
Pour les personnes qui choisissent de ne retenir que les outils de base du travail quotidien et qui souhaitent accepter des solutions moins élégantes et moins efficaces:
head -n $(grep -n pattern filename | cut -d: -f1) filename
Si cette commande concerne un script, je rechercherai des solutions plus élégantes (et éventuellement plus efficaces). S'il s'agit d'une commande unique ou d'un script à jeter, je m'en fiche.
Vous pouvez également utiliser l'un des éléments suivants
tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac
ou
tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac
ou
tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac
La première option est très similaire à celle suggérée par le PO, elle s'assure seulement de montrer suffisamment de lignes avant le contexte en comptant les lignes du fichier.
La deuxième option recherche le numéro de ligne de la première correspondance (vous pouvez également changer cela en modifiant la "tête" intérieure) et utilise ensuite tête sur ce numéro.
La dernière option remplace toutes les nouvelles lignes par la correspondance et que remplace deux correspondances adjacentes par une nouvelle ligne. La sortie de ceci est une ligne pour chaque bloc de texte entre deux correspondances. Après cela, il utilise 'head' pour choisir la première ligne (lier le bloc de texte jusqu'à la première correspondance) et reconvertit chaque correspondance en une nouvelle ligne. cette option ne fonctionne que si le fichier est au format suivant
pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern
texttexttext
texttexttexttexttexttexttexttexttext
et ainsi de suite
sed
commande au bas de la page est un peu maladroite.