Correspondance des expressions rationnelles non gourmandes (réticentes) dans sed?

J’essaie d’utiliser sed pour nettoyer les lignes d’URL afin d’extraire uniquement le domaine.

Donc de:

http://www.suepearson.co.uk/product/174/71/3816/ 

Je veux:

http://www.suepearson.co.uk/

(avec ou sans le slash de formation, peu importe)

J’ai essayé:

  sed 's|\(http:\/\/.*?\/\).*|\1|' 

et (échappant au quantificateur non gourmand)

 sed 's|\(http:\/\/.*\?\/\).*|\1|' 

mais je n’arrive pas à faire fonctionner le quantificateur non gourmand, donc il finit toujours par correspondre à la chaîne entière.

Ni la regex Posix / GNU ni celle de base ne reconnaît le quantificateur non gourmand; vous avez besoin d’une regex plus tard. Heureusement, Perge Regex pour ce contexte est assez facile à obtenir:

 perl -pe 's|(http://.*?/).*|\1|' 

Essayez [^/]* au lieu de .*? :

 sed 's|\(http://[^/]*/\).*|\1|g' 

Avec sed, j’applique généralement une recherche non gourmande en recherchant autre chose que le séparateur jusqu’au séparateur:

 echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p' 

Sortie:

 http://www.suon.co.uk 

c’est:

  • ne pas sortir -n
  • rechercher, faire correspondre le motif, remplacer et imprimer s///p
  • utiliser ; séparateur de commande de recherche au lieu de / pour faciliter la saisie, s;;;p
  • rappelez la correspondance entre parenthèses \(\) , accessible ultérieurement avec \1 , \2
  • correspond à http://
  • suivi de tout ce qui figure entre parenthèses [] , [ab/] signifierait soit a ou b ou /
  • premier ^ in [] signifie not , donc suivi de tout sauf de la chose dans le []
  • donc [^/] signifie tout sauf le caractère /
  • * répète le groupe précédent, donc [^/]* signifie caractères sauf / .
  • si loin sed -n 's;\(http://[^/]*\) signifie rechercher et se souvenir de http:// suivi de tous les caractères sauf / et se rappeler de ce que vous avez trouvé
  • nous voulons rechercher jusqu’à la fin du domaine alors arrêtez sur le prochain / alors ajoutez un autre / à la fin: sed -n 's;\(http://[^/]*\)/' mais nous voulons correspondre à la rest de la ligne après le domaine alors ajoutez .*
  • maintenant la correspondance mémorisée dans le groupe 1 ( \1 ) est le domaine, donc remplacez la ligne correspondante par des éléments enregistrés dans le groupe \1 et imprimez: sed -n 's;\(http://[^/]*\)/.*;\1;p'

Si vous souhaitez également inclure une barre oblique inverse après le domaine, ajoutez une barre oblique inverse supplémentaire dans le groupe pour vous en souvenir:

 echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p' 

sortie:

 http://www.suon.co.uk/ 

sed ne supporte pas l’opérateur “non gourmand”.

Vous devez utiliser l’opérateur “[]” pour exclure “/” de la correspondance.

 sed 's,\(http://[^/]*\)/.*,\1,' 

PS, il n’est pas nécessaire de revenir en arrière “/”.

Solution non gourmande pour plus d’un seul personnage

Ce sujet est vraiment vieux mais je suppose que les gens en ont encore besoin. Disons que vous voulez tout tuer jusqu’à la première occurrence de HELLO . Vous ne pouvez pas dire [^HELLO]

Donc, une bonne solution implique deux étapes, en supposant que vous pouvez épargner un mot unique que vous n’attendez pas dans l’entrée, par exemple top_sekrit .

Dans ce cas, nous pouvons:

 s/HELLO/top_sekrit/ #will only replace the very first occurrence s/.*top_sekrit// #kill everything till end of the first HELLO 

Bien sûr, avec une saisie plus simple, vous pouvez utiliser un mot plus petit, voire un seul caractère.

HTH!

Simulation d’un quantificateur paresseux (non gourmand) dans sed

Et toutes les autres saveurs de regex!

  1. Recherche de la première occurrence d’une expression:

    • POSIX ERE (en utilisant l’option -r )

      Regex:

       (EXPRESSION).*|. 

      Sed:

       sed -r "s/(EXPRESSION).*|./\1/g" # Global `g` modifier should be on 

      Exemple (trouver la première séquence de chiffres) Démo en direct :

       $ sed -r "s/([0-9]+).*|./\1/g" < << "foo 12 bar 34" 
       12 

      Comment ça marche ?

      Cette regex bénéficie d'une alternance | . A chaque position, le moteur cherchera le premier côté de l'alternance (notre cible) et s'il ne correspond pas au second côté de l'alternance qui a un point . correspond au prochain personnage immédiat.

      entrer la description de l'image ici

      Comme l'indicateur global est défini, le moteur tente de continuer à faire correspondre le caractère à la fin de la chaîne d'entrée ou à notre cible. Dès que le premier et le seul groupe de capture du côté gauche de l'alternance correspond (EXPRESSION) rest de la ligne est également consommé immédiatement. Nous tenons maintenant notre valeur dans le premier groupe de capture.

    • POSIX BRE

      Regex:

       \(\(\(EXPRESSION\).*\)*.\)* 

      Sed:

       sed "s/\(\(\(EXPRESSION\).*\)*.\)*/\3/" 

      Exemple (trouver la première séquence de chiffres):

       $ sed "s/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/" < << "foo 12 bar 34" 
       12 

      Celui-ci est comme la version ERE mais sans aucune alternance. C'est tout. À chaque position, le moteur essaie de faire correspondre un chiffre.

      entrer la description de l'image ici

      S'il est trouvé, les autres chiffres suivants sont consommés et capturés et le rest de la ligne est immédiatement mis en correspondance, sinon * signifie plus ou zéro saute le second groupe de capture \(\([0-9]\{1,\}\).*\)* et arrive à un point . pour correspondre à un seul caractère et ce processus continue.

  2. Recherche de la première occurrence d'une expression délimitée :

    Cette approche correspond à la toute première occurrence d'une chaîne délimitée. Nous pouvons l'appeler un bloc de chaîne.

     sed "s/\(END-DELIMITER-EXPRESSION\).*/\1/; \ s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g" 

    Chaîne d'entrée:

     foobar start block #1 end barfoo start block #2 end 

    -EDE: end

    -SDE: start

     $ sed "s/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g" 

    Sortie:

     start block #1 end 

    Première regex \(end\).* Correspond et capture la fin du délimiteur de la première end et les substituants correspondent tous aux caractères capturés récents, qui sont le délimiteur de fin. A ce stade, notre sortie est la suivante: foobar start block #1 end .

    entrer la description de l'image ici

    Ensuite, le résultat est transmis à la deuxième regex \(\(start.*\)*.\)* Identique à la version POSIX BRE ci-dessus. Il correspond à un seul caractère si le début du délimiteur de start ne correspond pas, sinon il correspond et capture le délimiteur de début et correspond aux autres caractères.

    entrer la description de l'image ici


Répondre directement à votre question

En utilisant l'approche n ° 2 (expression délimitée), vous devez sélectionner deux expressions appropriées:

  • EDE: [^:/]\/

  • SDE: http:

Usage:

 $ sed "s/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/" < << "http://www.suepearson.co.uk/product/174/71/3816/" 

Sortie:

 http://www.suepearson.co.uk/ 

Cela peut être fait en utilisant cut:

 echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3 

sed – correspondance non gourmande par Christoph Sieghart

L’astuce pour obtenir une correspondance non gourmande dans sed consiste à faire correspondre tous les caractères à l’exception de celui qui termine la correspondance. Je sais, une évidence, mais j’ai gaspillé de précieuses minutes là-dessus et les scripts shell devraient être, après tout, rapides et faciles. Donc, si quelqu’un d’autre en avait besoin:

Correspondance gourmande

 % echo "foobar" | sed 's/< .*>//g' bar 

Correspondance non gourmande

 % echo "foobar" | sed 's/< [^>]*>//g' foobar 

une autre façon, ne pas utiliser regex, est d’utiliser la méthode champs / délimiteur, par exemple

 ssortingng="http://www.suepearson.co.uk/product/174/71/3816/" echo $ssortingng | awk -F"/" '{print $1,$2,$3}' OFS="/" 

sed certainement sa place mais ce n’est pas le cas!

Comme Dee l’a souligné: il suffit d’utiliser cut . C’est beaucoup plus simple et beaucoup plus sûr dans ce cas. Voici un exemple où nous extrayons divers composants de l’URL en utilisant la syntaxe Bash:

 url="http://www.suepearson.co.uk/product/174/71/3816/" protocol=$(echo "$url" | cut -d':' -f1) host=$(echo "$url" | cut -d'/' -f3) urlhost=$(echo "$url" | cut -d'/' -f1-3) urlpath=$(echo "$url" | cut -d'/' -f4-) 

vous donne:

 protocol = "http" host = "www.suepearson.co.uk" urlhost = "http://www.suepearson.co.uk" urlpath = "product/174/71/3816/" 

Comme vous pouvez le constater, cette approche est beaucoup plus flexible.

(tout crédit à Dee)

 sed 's|(http:\/\/[^\/]+\/).*|\1|' 

sed -E interprète les expressions régulières comme des expressions régulières (modernes) étendues

Mise à jour: -E sur MacOS X, -r dans GNU sed.

Il y a encore de l’espoir de résoudre ce problème en utilisant pure (GNU) sed. Bien que ce ne soit pas une solution générique dans certains cas, vous pouvez utiliser des “boucles” pour éliminer toutes les parties inutiles de la chaîne comme ceci:

 sed -r -e ":loop" -e 's|(http://.+)/.*|\1|' -e "t loop" 
  • -r: Utilise l’expression rationnelle étendue (pour les parenthèses + et non échappées)
  • “: loop”: Définit une nouvelle étiquette nommée “loop”
  • -e: ajoute des commandes à sed
  • “t loop”: Revient à l’étiquette “loop” s’il y a eu une substitution réussie

Le seul problème ici est qu’il va également couper le dernier caractère séparateur (‘/’), mais si vous en avez vraiment besoin, vous pouvez toujours le remettre après la “boucle” terminée, ajoutez simplement cette commande supplémentaire à la fin du précédent. ligne de commande:

 -e "s,$,/," 

Parce que vous avez spécifiquement indiqué que vous essayez d’utiliser sed (au lieu de perl, cut, etc.), essayez de le regrouper. Cela évite que l’identifiant non gourmand ne soit potentiellement reconnu. Le premier groupe est le protocole (c’est-à-dire “http: //”, “https: //”, “tcp: //”, etc.). Le deuxième groupe est le domaine:

 echo "http://www.suon.co.uk/product/1/7/3/" |  sed "s | ^ \ (. * // \) \ ([^ /] * \). * $ | \ 1 \ 2 |"

Si vous n’êtes pas familier avec le regroupement, commencez ici .

Je me rends compte que c’est une ancienne entrée, mais quelqu’un peut le trouver utile. Le nom de domaine complet ne pouvant pas dépasser 253 caractères, remplacez. * Par. \ {1, 255 \}

 echo "/home/one/two/three/myfile.txt" | sed 's|\(.*\)/.*|\1|' 

don bother, je l’ai eu sur un autre forum 🙂

sed 's|\(http:\/\/www\.[az.0-9]*\/\).*|\1| travaille aussi

Une autre version sed:

 sed 's|/[:alphanum:].*||' file.txt 

Il correspond / suivi d’un caractère alphanumérique (donc pas une autre barre oblique) ainsi que le rest des caractères jusqu’à la fin de la ligne. Ensuite, il le remplace par rien (c.-à-d. Le supprime).

Voici quelque chose que vous pouvez faire avec une approche en deux étapes et awk:

 A=http://www.suepearson.co.uk/product/174/71/3816/ echo $A|awk ' { var=gensub(///,"||",3,$0) ; sub(/\|\|.*/,"",var); print var }' 

Sortie: http://www.suepearson.co.uk

J’espère que cela pourra aider!

Ceci est la façon de faire une correspondance robuste avec des chaînes multi-caractères utilisant sed. Disons que vous voulez changer chaque foo...bar en , par exemple cette entrée:

 $ cat file ABC foo DEF bar GHI foo KLM bar NOP foo QRS bar TUV 

devrait devenir cette sortie:

 ABC  GHI  NOP  TUV 

Pour ce faire, convertissez toto et barre en caractères individuels, puis utilisez la négation de ces caractères entre eux:

 $ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/< &>/g; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file ABC  GHI  NOP  TUV 

Au dessus:

  1. s/@/@A/g; s/{/@B/g; s/}/@C/g s/@/@A/g; s/{/@B/g; s/}/@C/g convertit { et } en chaînes d’espace réservé qui ne peuvent pas exister dans l’entrée afin que ces caractères soient disponibles pour convertir foo et bar en.
  2. s/foo/{/g; s/bar/}/g s/foo/{/g; s/bar/}/g convertit respectivement foo et bar en { et }
  3. s/{[^{}]*}/< &>/g exécute l’opération que nous voulons – convertir foo...bar en
  4. s/}/bar/g; s/{/foo/g s/}/bar/g; s/{/foo/g convertit { et } en foo et bar .
  5. s/@C/}/g; s/@B/{/g; s/@A/@/g s/@C/}/g; s/@B/{/g; s/@A/@/g convertit les chaînes d’espace réservé en leurs caractères d’origine.

Notez que ce qui précède ne dépend d’aucune chaîne particulière n’étant pas présente dans l’entrée car elle fabrique de telles chaînes dans la première étape, et ne se soucie pas non plus de l’occurrence d’une expression rationnelle particulière à laquelle vous souhaitez vous connecter. {[^{}]*} autant de fois que nécessaire dans l’expression pour isoler la correspondance souhaitée et / ou avec l’opérateur de correspondance numérique seds, par exemple pour ne remplacer que la deuxième occurrence:

 $ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/< &>/2; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file ABC foo DEF bar GHI  NOP foo QRS bar TUV