web-dev-qa-db-fra.com

Extraire la chaîne de la chaîne à l'aide de RegEx dans le terminal

J'ai une chaîne comme first url, second url, third url Et je souhaite extraire uniquement le url après le mot second dans le terminal OS X (uniquement la première occurrence). Comment puis-je le faire?

Dans mon éditeur préféré J'ai utilisé l'expression régulière /second (url)/ et utilisé $1 Pour l'extraire, je ne sais tout simplement pas comment le faire dans le Terminal.

Gardez à l'esprit que url est une URL réelle, je vais utiliser l'une de ces expressions pour la faire correspondre: Regex pour correspondre à l'URL

37
fregante
echo 'first url, second url, third url' | sed 's/.*second//'

Edit: j'ai mal compris. Mieux:

echo 'first url, second url, third url' | sed 's/.*second \([^ ]*\).*/\1/'

ou:

echo 'first url, second url, third url' | Perl -nle 'm/second ([^ ]*)/; print $1'
54
Sjoerd

La tuyauterie vers un autre processus (comme "sed" et "Perl" suggéré ci-dessus) peut être très coûteuse, en particulier lorsque vous devez exécuter cette opération plusieurs fois. Bash prend en charge l'expression rationnelle:

[["string" = ~ regex]]

De la même manière que vous extrayez des correspondances dans votre éditeur préféré en utilisant $1, $2, etc., Bash remplit le $BASH_REMATCH tableau avec toutes les correspondances.

Dans votre exemple particulier:

str="first usr1, second url2, third url3"
if [[ $str =~ (second )([^,]*) ]]; then echo "match: '${BASH_REMATCH[2]}'"; else echo "no match found"; fi

Production:

match: 'url2'

Plus précisément, =~ prend en charge les expressions régulières étendues telles que définies par POSIX , mais avec spécifique à la plate-forme extensions (dont l'étendue varie et peuvent être incompatibles).
Sur les plateformes Linux (GNU userland), voir man grep; sur les plates-formes macOS/BSD, voir man re_format.

13
Dmitry Shevkoplyas

Dans l'autre réponse, à condition que vous restiez avec tout après l'URL souhaitée. Je vous propose donc la solution suivante.

echo 'first url, second url, third url' | sed 's/.*second \(url\)*.*/\1/'

Sous sed, vous regroupez une expression en échappant aux parenthèses qui l'entourent (norme POSIX).

7
mhitza

En essayant ceci, ce que vous avez probablement oublié était le -E argument pour sed.

De sed --help:

  -E, -r, --regexp-extended
                 use extended regular expressions in the script
                 (for portability use POSIX -E).

Vous n'avez pas besoin de modifier votre expression régulière de manière significative, mais vous devez ajouter .* pour correspondre avidement autour de lui pour supprimer l'autre partie de la chaîne.

Cela fonctionne bien pour moi:

echo "first url, second url, third url" | sed -E 's/.*second (url).*/\1/'

Production:

url

Dans lequel la sortie "url" est en fait la deuxième instance de la chaîne. Mais si vous savez déjà qu'il est formaté entre virgule et espace, et que vous n'autorisez pas ces caractères dans les URL, alors l'expression régulière [^,]* devrait être bien.

En option:

echo "first http://test.url/1, second ://test.url/with spaces/2, third ftp://test.url/3" \
     | sed -E 's/.*second ([a-zA-Z]*:\/\/[^,]*).*/\1/'

Qui sort correctement:

://example.com/with spaces/2
2
Yeti