Estrai la sottostringa usando regexp in plain bash


97

Sto cercando di estrarre l'ora da una stringa usando bash e ho difficoltà a capirlo.

La mia stringa è così:

US/Central - 10:26 PM (CST)

E voglio estrarre la 10:26parte.

Qualcuno conosce un modo per farlo solo con bash - senza usare sed, awk, ecc.?

Ad esempio, in PHP userei - non il modo migliore, ma funziona - qualcosa del tipo:

preg_match( ""(\d{2}\:\d{2}) PM \(CST\)"", "US/Central - 10:26 PM (CST)", $matches );

Grazie per qualsiasi aiuto, anche se la risposta utilizza sed o awk

Risposte:


207

Utilizzando pure :

$ cat file.txt
US/Central - 10:26 PM (CST)
$ while read a b time x; do [[ $b == - ]] && echo $time; done < file.txt

un'altra soluzione con bash regex:

$ [[ "US/Central - 10:26 PM (CST)" =~ -[[:space:]]*([0-9]{2}:[0-9]{2}) ]] &&
    echo ${BASH_REMATCH[1]}

un'altra soluzione che utilizza grepe guarda intorno all'espressione regolare avanzata:

$ echo "US/Central - 10:26 PM (CST)" | grep -oP "\-\s+\K\d{2}:\d{2}"

un'altra soluzione usando sed:

$ echo "US/Central - 10:26 PM (CST)" |
    sed 's/.*\- *\([0-9]\{2\}:[0-9]\{2\}\).*/\1/'

un'altra soluzione che utilizza perl:

$ echo "US/Central - 10:26 PM (CST)" |
    perl -lne 'print $& if /\-\s+\K\d{2}:\d{2}/'

e l'ultimo usando awk:

$ echo "US/Central - 10:26 PM (CST)" |
    awk '{for (i=0; i<=NF; i++){if ($i == "-"){print $(i+1);exit}}}'

Freddo! C'è qualche possibilità che io usi anche il trattino "-" nel pattern? perché quel grep restituisce alcune corrispondenze, e a me interessa solo quella che ha il trattino e poi uno spazio e poi l'ora .....
andrux

Probabilmente avrei potuto ottenere la soluzione perl, ma è un vantaggio eccellente. Grazie!
andrux

aggiunto awk one for fun =)
Gilles Quenot

1
Grazie per avermi fatto sapere il \ K "trucco". grep con sintassi perl è davvero potente.
Marco Sulla

1
Mi piace la sedversione, ma volevo avvertire gli altri che sednon richiede necessariamente un +modificatore. Un modo per aggirare è usare il {1, }modificatore per abbinare uno o più.
CodeBrew

89
    echo "US/Central - 10:26 PM (CST)" | sed -n "s/^.*-\s*\(\S*\).*$/\1/p"

-n      suppress printing
s       substitute
^.*     anything at the beginning
-       up until the dash
\s*     any space characters (any whitespace character)
\(      start capture group
\S*     any non-space characters
\)      end capture group
.*$     anything at the end
\1      substitute 1st capture group for everything on line
p       print it

8
Sento che questo mi ha reso un maestro di sed istantaneo. Una buona opzione che posso modificare è meglio di nove non capisco.
Noumenon,

Grazie per la spiegazione dettagliata, aiuta a evitare futuri post "come faccio a regexp XXXX".
Studgeek

4
Potresti spiegare perché prima sopprimi la stampa con e -npoi richiedi di nuovo la stampa con /p? Non sarebbe lo stesso omettere la -nbandiera e omettere la /pdirettiva? Grazie.
Victor Zamanian

Bella risposta ! Grazie per il vostro aiuto :-)
Bruno Lavit

1
@VictorZamanian da qui : "Per impostazione predefinita, sed stampa ogni riga. Se effettua una sostituzione, il nuovo testo viene stampato al posto di quello vecchio. Se usi un argomento opzionale per sed," sed -n ", non lo farà, per impostazione predefinita, stampa tutte le nuove righe ... Quando viene utilizzata l'opzione "-n", il flag "p" causerà la stampa della riga modificata. "
tdashroy

26

Tecnica di chop-chop veloce e sporca, priva di regex e di bassa robustezza

string="US/Central - 10:26 PM (CST)"
etime="${string% [AP]M*}"
etime="${etime#* - }"

5
È così disgustosamente sporco che mi vergogno di non averci pensato io stesso. Anche +1 | read zone dash time apm zonefunziona
Orwellophile

Molto pulito ed evita le chiamate a programmi esterni.
Victor Zamanian

8
Salve, questo sarebbe 10 volte più utile se includesse un riferimento a ulteriore documentazione o alcuni nomi attorno alla tecnica in modo che le persone possano andare a cercare di più. Per gli interessati, questa è la manipolazione delle stringhe bash e puoi trovare maggiori dettagli qui: tldp.org/LDP/abs/html/string-manipulation.html
Pedro Mata-Mouros

0

Se la tua stringa è

foo="US/Central - 10:26 PM (CST)"

poi

echo "${foo}" | cut -d ' ' -f3

farà il lavoro.


1
o cut -c14-18ovviamente solo finché la posizione del personaggio non cambia. cosa che non dovrebbe accadere se il fuso orario è corretto.
Markus

Sir domanda è chiesto per regex non per cut
indrajit narvekar
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.