Extrahieren Sie den Teilstring mit Regexp in einer einfachen Bash

96

Ich versuche, die Zeit mit Bash aus einem String zu extrahieren, und es fällt mir schwer, das herauszufinden.

Meine Zeichenfolge ist wie folgt:

US/Central - 10:26 PM (CST)

Und ich möchte das 10:26Teil extrahieren .

Kennt jemand einen Weg, dies nur mit Bash zu tun - ohne sed, awk usw. zu verwenden?

Wie in PHP würde ich verwenden - nicht der beste Weg, aber es funktioniert - so etwas wie:

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

Vielen Dank für jede Hilfe, auch wenn die Antwort sed oder awk verwendet

Andrux
quelle

Antworten:

206

Mit rein ::

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

eine andere Lösung mit Bash Regex:

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

eine andere Lösung, grepdie fortgeschrittenen regulären Ausdruck verwendet und sich umschaut:

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

eine andere Lösung mit sed:

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

eine andere Lösung mit Perl:

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

und letzte mit awk:

$ echo "US/Central - 10:26 PM (CST)" |
    awk '{for (i=0; i<=NF; i++){if ($i == "-"){print $(i+1);exit}}}'
Gilles Quenot
quelle
Cool! Gibt es eine Chance, dass ich auch den Bindestrich "-" im Muster verwende? weil dieser grep einige Übereinstimmungen zurückgibt, und ich bin nur an dem interessiert, der den Bindestrich und dann ein Leerzeichen und dann die Zeit hat .....
andrux
Ich hätte wahrscheinlich die Perl-Lösung haben können, aber es ist ein ausgezeichnetes Plus. Vielen Dank!
Andrux
awk one zum Spaß hinzugefügt =)
Gilles Quenot
1
Vielen Dank, dass Sie mich über den \ K "Trick" informiert haben. grep mit Perl-Syntax ist wirklich mächtig.
Marco Sulla
1
Ich mag die sedVersion, wollte aber andere warnen, seddie nicht unbedingt +Modifikator benötigen. Eine Möglichkeit, dies zu {1, }umgehen, besteht darin, einen oder mehrere Modifikatoren zu verwenden.
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
jgshawkey
quelle
8
Ich habe das Gefühl, das hat mich sofort zu einem Meister gemacht. Eine gute Option, die ich optimieren kann, ist besser als neun, die ich nicht verstehe.
Noumenon
Vielen Dank für die ausführliche Erklärung, um zukünftige "Wie regexpiere ich XXXX" -Postings zu vermeiden.
Studgeek
4
Können Sie erklären, warum Sie zuerst das Drucken mit unterdrücken und -ndann das Drucken mit erneut anfordern /p? Wäre es nicht dasselbe, die -nFlagge und die /pRichtlinie wegzulassen ? Vielen Dank.
Victor Zamanian
Gute Antwort ! Vielen Dank für Ihre Hilfe :-)
Bruno Lavit
1
@ VictorZamanian von hier : "Standardmäßig druckt sed jede Zeile. Wenn eine Ersetzung vorgenommen wird, wird der neue Text anstelle des alten gedruckt. Wenn Sie ein optionales Argument für sed verwenden," sed -n ", wird dies nicht. Drucken Sie standardmäßig alle neuen Zeilen. ... Wenn die Option "-n" verwendet wird, bewirkt das Flag "p", dass die geänderte Zeile gedruckt wird. "
tdashroy
26

Schnelle, schmutzige, regexfreie Chop-Chop-Technik mit geringer Robustheit

string="US/Central - 10:26 PM (CST)"
etime="${string% [AP]M*}"
etime="${etime#* - }"
doubleDown
quelle
5
Das ist so ekelhaft dreckig, dass ich mich schäme, dass ich selbst nicht daran gedacht habe. +1 | read zone dash time apm zonefunktioniert auch
Orwellophile
Sehr sauber und vermeidet Aufrufe externer Programme.
Victor Zamanian
8
Hallo, dies wäre 10x nützlicher, wenn es einen Verweis auf weitere Dokumentationen oder einige Namen rund um die Technik enthalten würde, damit die Leute losgehen und mehr recherchieren könnten. Für Interessierte ist dies eine Bash-String-Manipulation. Weitere Informationen finden Sie hier: tldp.org/LDP/abs/html/string-manipulation.html
Pedro Mata-Mouros
0

Wenn deine Zeichenfolge ist

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

dann

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

wird den Job machen.

LeChatDeNansen
quelle
1
oder cut -c14-18natürlich nur solange sich die Charakterposition nicht ändert. Dies sollte nicht passieren, wenn die Zeitzone festgelegt ist.
Markus
Sir Frage wird für Regex nicht für Cut
Indrajit Narvekar