Comment puis-je tout supprimer jusqu'à ce qu'un motif et tout ce qui suit un autre motif d'une ligne?

17

Dans le fichier suivant:

Lorem ipsum dolor assis amet, élit adipiscing consectetuer. Ut eu metus id lectus vestibulum ultrices. Maecenas rhoncus.

Je veux tout supprimer avant consectetueret tout après elit.

Ma sortie souhaitée:

consectetuer adipiscing elit.

Comment puis-je faire ceci?

manuel
la source
2
La commande peut être sed. Cela peut aussi être perl, ou même pur bash.
muru
@manuel Si l'une de ces réponses a résolu votre problème, veuillez prendre un moment et l' accepter en cliquant sur la coche à gauche. Cela marquera la réponse à la question et c'est la façon dont les remerciements sont exprimés sur les sites Stack Exchange.
terdon

Réponses:

27

J'utiliserais sed

sed 's/^.*\(consectetuer.*elit\).*$/\1/' file

Décodage de la syntaxe sed s / find / replace /:

  • s/^.*- substitut commençant au début de la ligne ( ^) suivi de n'importe quoi ( .*) jusqu'à ...
  • \( - démarrer un bloc nommé
  • consectetuer.*elit\.- faire correspondre le premier mot, tout ( .*) jusqu'au dernier mot (dans ce cas, y compris le point de fin (échappé)) que vous souhaitez faire correspondre
  • \) - terminer le bloc nommé
  • faire correspondre tout le reste ( .*) à la fin de la ligne ( $)
  • / - terminer la section de recherche de substitut
  • \1- remplacer par le bloc de nom entre le \(et ce qui \)précède
  • / - terminer le remplacement
MikeV
la source
1
Bonne réponse, mais vous n'avez pas besoin de ^ou $puisque sed tentera de trouver la correspondance la plus longue. Vous pouvez également avoir raté le point après elit, vous pouvez insérer \.si nécessaire.
asoundmove
2
@asoundmove Bonne capture sur le point de fuite sur "elit". - vous avez un œil assez vif!. J'ai mis à jour ma réponse pour inclure le point échappé dans le motif. Vous avez également raison de dire que le ^et $ne sont pas nécessaires - je les ai laissés là car le questionneur a noté (à l'origine) qu'il était un peu débutant et cela peut être utile dans d'autres contextes.
MikeV
J'ai toujours copié-collé des solutions sed et les ai piratées pour répondre à mes besoins, mais grâce à cette réponse, j'ai l'impression de les comprendre maintenant. Grande réponse
Tyler
7

Si chaque ligne contient à la fois début et motif de fin alors la meilleure façon de le faire est avec grep. Au lieu de supprimer le début et la fin de chaque ligne, vous pouvez simplement afficher le contenu entre les deux modèles. L' -ooption dans GNU grepne produit que les correspondances:

grep -o 'consectetuer.*elit' file

Remarque: comme mentionné, cela ne fonctionne que si chaque ligne du fichier peut être analysée de cette façon. Là encore, c'est 80% de tous les cas d'utilisation typiques.

Slebetman
la source
1

Deux pour les boucles dans AWK:

$ awk '{for(i=1;i<=NF;i++) {if ($i == "consectetuer") beginning=i; if($i== "elit.") ending=i }; for (j=beginning;j<=ending;j++) printf $j" ";printf "\n"   }' file.txt 
consectetuer adipiscing elit.

Gsub d'AWK:

$ awk '{gsub(/^.*consectetuer/,"consectetuer"); gsub(/elit.*$/,"elit.");print}' file.txt
consectetuer adipiscing elit.
Sergiy Kolodyazhnyy
la source
1

Une façon Perl. C'est essentiellement la même chose que lased réponse de MikeV :

perl -pe 's/.*(consectetuer.*elit).*./$1/' file

Le -pmoyen "imprime chaque ligne après avoir appliqué le script fourni avec -e". Le s/foo/bar/est l'opérateur de substitution; il remplacera foopar bar. Les parenthèses capturent un motif et utilisons-le dans le remplacement. Le premier motif capturé est $1le second $2et ainsi de suite.

Ainsi, la commande fera correspondre tout jusqu'à consectetuer( .*consectetuer), puis tout jusqu'à elit( .*elit) et tout le reste jusqu'à la fin de la ligne ( .*) et remplacera cela par le motif capturé.

terdon
la source
1

Je ne sais pas pourquoi ce titre de question a été modifié " du fichier " en " d'une ligne " alors que l'OP n'exclut pas la possibilité sur plusieurs lignes même si l'exemple semble être une seule ligne. Quoi qu'il en soit, il pourrait être utile de fournir ici une solution à plusieurs lignes.

Cela fonctionne pour les lignes croisées:

from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"

Exemples:

[xiaobai@xiaobai tmp]$ cat file
1
abc consectetuer lsl

home

def elit dd
2 consectetuer ABC elit
[xiaobai@xiaobai tmp]$ from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"
consectetuer lsl

home

def elit
[xiaobai@xiaobai tmp]$ 

référence: Expansion des paramètres du shell

林果 皞
la source
1
C'est parfait!
Clément