2012-05-14 7 views
6

Ho problemi a catturare le cifre in una stringa di questo formato (t|b|bug_|task_|)1234 utilizzando un'espressione regolare di bash. Il sotto non funziona:Come abbinare un "qualcosa o niente" in una regex di bash?

[[ $current_branch =~ ^(t|b|bug_|task_|)([0-9]+) ]] 

Ma una volta che lo cambio a qualcosa di simile:

[[ $current_branch =~ ^(t|b|bug_|task_)([0-9]+) ]] 

funziona, ma naturalmente il suo male, perché non copre il caso in cui ci sono senza prefissi. Mi rendo conto che in questo caso ho potuto fare

[[ $current_branch =~ ^(t|b|bug_|task_)?([0-9]+) ]] 

e ottenere lo stesso risultato, ma mi piacerebbe sapere perché il secondo esempio non funziona. Ad esempio, la regex sembra funzionare bene in Ruby.

(Questo è il GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11), OSX Lion)

+0

Hai provato '(^ t |^b |^bug_ |^task_ |^$) ...' (o simile)?E non è il carattere * * char = 'il qualcosa o nulla' carattere jolly? In bocca al lupo. – shellter

+1

'[[23 = ~ = ~^(t | b | bug_ | task_ |) ([0-9] +)]]] funziona per me. Qual è un esempio di '$ current_branch' non funzionante? Cosa costituisce "non funziona"? Quale versione di Bash? –

+0

Quindi la domanda è: perché non '[[$ current_branch = ~^(t | b | bug_ | task_ |) ([0-9] +)]]' corrisponde, ad esempio, '123'? – RichardTowers

risposta

2

Sono certo che la differenza tra versioni funzionanti e non funzionanti del regex si basano sui diversi modi di leggere regex (7). Ho intenzione di citare tutta la parte pertinente, perché penso che va al cuore del problema:


Le espressioni regolari ("re" s), come definito nella POSIX.2, venire in due forme: moderne RE (approssimativamente quelle di egrep; POSIX.2 chiama questi "estesi" RE) e obsolete RE (approssimativamente quelle di ed (1); POSIX.2 "base" RE). Esistono principalmente OB obsoleti per compatibilità con le versioni precedenti in alcuni vecchi programmi; saranno discussi alla fine . POSIX.2 lascia aperti alcuni aspetti della sintassi RE e della semantica; "(!)" contrassegna le decisioni su questi aspetti che potrebbero non essere completamente trasferibili ad altre implementazioni POSIX.2 .

Un (moderno) RE è uno (!) O più non vuoto (!) rami, separati da '|'. È corrisponde a tutto ciò che corrisponde a uno dei rami.

Un ramo è uno (!) O più pezzi, concatenato. Si abbina un match per il prima, seguita da una corrispondenza per il secondo, ecc

Un pezzo è un atomo di eventualmente seguito da un singolo (!) '*', '+', '?', oppure legato. Un atomo seguito da '*' corrisponde ad una sequenza di 0 o più corrispondenze dell'atomo. Un atomo seguito da "+" corrisponde a una sequenza di 1 o più corrispondenze dell'atomo. Un atomo seguito da "?" corrisponde a una sequenza di 0 o 1 corrispondenze dell'atomo.

Un limite è '{' seguita da un numero intero senza segno decimale, eventualmente seguito da '' eventualmente seguito da un altro intero decimale senza segno, sempre seguito da '}'. Gli interi devono essere compresi tra 0 e RE_DUP_MAX (255 (!)) Inclusi, e se ce ne sono due, il primo non può superare il secondo.Un atomo seguito da un limite contenente un intero i e nessuna virgola corrisponde a una sequenza di esattamente le corrispondenze dell'atomo. Un atomo seguito da un limite contenente uno numero intero i e una virgola corrisponde a una sequenza di i o più corrispondenze dell'atomo. Un atomo seguito da un limite contenente due interi i e j corrisponde a una sequenza di da corrispondenze i j (incluse) dell'atomo.

Un atomo è un'espressione regolare racchiusa in "()" (corrispondente ad una corrispondenza per l' espressione regolare), un insieme vuoto di "()" (corrispondente alla stringa nulla) (!), Un'espressione staffa (vedi sotto), '.' (corrispondente a ogni singolo carattere), '^' (corrispondente alla stringa nulla all'inizio di una riga), '$' (corrispondente alla stringa nullo alla fine di una riga), un '\' seguito da uno dei caratteri "^. [$() | * +? {\" (corrispondente al carattere preso come carattere ordinario), un '\' seguito da qualsiasi altro carattere (!) (corrispondente al carattere assunto come carattere ordinario , come se il '\' non fosse stato presente (!)), o un singolo carattere senza altro significato (corrispondente a quel carattere). Un '{' seguito da un carattere diverso da una cifra è un carattere normale, non l'inizio di un limite (!) . È illegale terminare un RE con '\'.


OK, c'è un bel po 'qui per disfare. Prima di tutto, nota che il simbolo "(!)" Indica che esiste un problema aperto o non portatile.

La questione essenziale è proprio nel paragrafo successivo:

A (moderna) RE è uno o più rami non vuoto , separati da '|' (!) (!).

Il tuo caso è che hai una filiale vuota. Come puoi vedere da "(!)", Il ramo vuoto è un problema aperto o non portatile. Penso che questo sia il motivo per cui funziona su alcuni sistemi ma non su altri. (L'ho testato su Cygwin 4.1.10 (4) -release, e non ha funzionato, quindi su Linux 3.2.25 (1) -release, e ha funzionato.I due sistemi hanno pagine man equivalenti, ma non identiche per regex7.)

Supponendo che i rami debbano essere non vuoti, un ramo può essere un pezzo, che può essere un atomo.

Un atomo può essere "un insieme vuoto di"() "(corrispondente alla stringa nulla) (!)". <sarcasm> Beh, è ​​davvero d'aiuto. </sarcasm> Quindi, POSIX specifica un'espressione regolare per la stringa vuota, ad esempio (), ma aggiunge anche un "(!)" Per dire che si tratta di un problema aperto o non portatile.

Dal momento che ciò che stai cercando è un ramo che corrisponde alla stringa vuota, provare

[[ $current_branch =~ ^(t|b|bug_|task_|())([0-9]+) ]] 

che utilizza la regex () per abbinare la stringa vuota. (Questo ha funzionato per me nella shell Cygwin 4.1.10 (4), in cui la regex originale non funzionava.)

Tuttavia, mentre (si spera) questo suggerimento funzionerà per voi nella configurazione attuale, non c'è garantire che sarà portatile. Mi dispiace deludere.

+0

Wow, una risposta davvero superba! Grazie per il tuo duro lavoro! – Suan

+0

Sfortunatamente ora sembra che corrisponda a tutto, qualcosa di semplice come '[[" $ foo "= ~^(bar |())]]' corrisponderà se 'foo = baz' ecc., Comprese tutte le variabili che sono vuote. Alla fine ho optato per '^ $', che in effetti funziona. GNU bash, versione 4.4.12 (1) -release (x86_64-redhat-linux-gnu) – xenithorb

0

[[ $current_branch =~ ^(t|b|bug_|task_|)([0-9]+) ]] opere per me in bash 4.1.2, ma fallisce in bash 3.2.48. Potrebbe essere solo un bug che è stato risolto tra le due versioni.

+0

Non è direttamente correlata alla versione di bash - vedi la mia risposta. – JXG

Problemi correlati