web-dev-qa-db-fra.com

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

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 consectetuer et tout après elit.

Ma sortie souhaitée:

consectetuer adipiscing elit.

Comment puis-je faire ceci?

17
manuel

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 tout (.*) Jusqu'à...
  • \( - démarre un bloc nommé
  • consectetuer.*elit\. - correspond au premier mot, tout (.*) jusqu'au dernier mot (dans ce cas, y compris le point de fin (d'échappement)) que vous souhaitez faire correspondre
  • \) - termine le bloc nommé
  • faire correspondre tout le reste (.*) jusqu'à la fin de la ligne ($)
  • / - termine la section de recherche de substitution
  • \1 - remplacez par le bloc de nom entre le \( et le \) au dessus de
  • / - terminer le remplacement
28
MikeV

Si chaque ligne contient à la fois un motif de début et un motif de fin, la façon la plus simple de le faire est d'utiliser 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. Le -o option dans GNU grep affiche uniquement 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.

7
slebetman

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.
1

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

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

Le -p signifie "imprimer chaque ligne après avoir appliqué le script donné avec -e". Le s/foo/bar/ est l'opérateur de substitution; il remplacera foo par bar. Les parenthèses capturent un motif et utilisons-le dans le remplacement. Le premier motif capturé est $1, la deuxième $2 etc.

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

1
terdon

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

1
林果皞