Espressione regolare in script bash


13

Questa è la mia prima volta che bash scripting quindi probabilmente sto facendo un errore facile.

Fondamentalmente, sto cercando di scrivere uno script che ottenga i gruppi di un utente e, se si trovano in un determinato gruppo, lo registrerà di conseguenza. Evidentemente ci saranno più funzionalità, ma non ha senso costruirlo quando non riesco nemmeno a far funzionare regex!

Finora ho questo:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Ogni posto in cui ho provato quella regex, funziona. Ma nello script bash, emette sempre e solo il $groups, seguito da No match. Quindi qualcuno può dirmi cosa c'è che non va?


1
Cosa ti fa pensare che qualcosa non vada?
arte

1
@jrdnhannah quindi prova a ricreare lentamente il tuo regexp target, prima abbina ^([a-zA-Z0-9\-_]+)poi aggiungi i due punti e così via ... Dovresti scoprire abbastanza presto, dov'è il problema.
peterph

2
Lo stesso qui con bash 4.2.45. L'escaping del carattere di sottolineatura l'ha risolto. Strano. @jrdnhannah potresti scriverlo come risposta e accettarlo per favore?
terdon

1
Dato che mi sono appena iscritto a Unix SE, mi richiede di aspettare 8 ore prima di rispondere al mio. Felice di contrassegnarlo come risposta se qualcun altro lo fa, però.
JRDN

4
@terdon bash chiama probabilmente le funzioni regex di libc, probabilmente. Quindi dipende dalla versione di libc, non dalla versione di bash. Vedi la mia risposta ... (O forse anche sulla sequenza di confronto che hai in uso)
derobert

Risposte:


14

Da man 7 regex:

Un'espressione di parentesi è un elenco di caratteri racchiuso tra "[]". ...

... Per includere un "-" letterale, rendilo il primo o l'ultimo personaggio ... [A] Tutti gli altri caratteri speciali, incluso '\', perdono il loro significato speciale all'interno di un'espressione tra parentesi.

Provare regexp con egrep dà un errore:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Ecco una versione più semplice, che dà anche un errore:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

Dal momento che \non è speciale, questa è una gamma, proprio come [a-z]sarebbe. Devi mettere il tuo -alla fine, come [_-]o:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Questo dovrebbe funzionare indipendentemente dalla versione di libc (in egrep o bash).

modifica: questo in realtà dipende anche dalle impostazioni locali. La manpage avverte di questo:

Gli intervalli dipendono molto dalla sequenza di fascicolazione e i programmi portatili dovrebbero evitare di fare affidamento su di essi.

Per esempio:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

Certo, anche se non ha commesso errori, non sta facendo quello che vuoi:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

Si tratta di una gamma, che in ASCII, comprende \, [, ^, e _.


Interessante. Il mio egrepnon dà alcun errore, corrisponde solo correttamente.
arte

@manatwork probabilmente la tua sequenza di confronto consente l'intervallo ....
derobert

Non so molto sulla collazione. Intendi questo LC_COLLATE="en_US.UTF-8":?
arte

@manatwork Ho modificato la domanda per fare un esempio. Nota che potrebbe essere diverso sul tuo sistema, perché a volte cambiano quelle sequenze di fascicolazione (ordinamento).
derobert,

1
@manatwork Va bene, ho quasi presentato una segnalazione di bug prima di notare il tentativo di fuga -...
derobert,

4

Regola generale con regexps (e qualsiasi bug in pezzi di codice più grandi): abbattilo e ricostruiscilo passo dopo passo o usa la bisecatura - qualunque cosa funzioni meglio per te.

In questo caso il colpevole si è rivelato essere il carattere di sottolineatura: fuggirlo con una barra rovesciata lo ha fatto funzionare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.