Ekstrak substring menggunakan regexp di bash biasa


97

Saya mencoba mengekstrak waktu dari string menggunakan bash, dan saya kesulitan memahaminya.

String saya seperti ini:

US/Central - 10:26 PM (CST)

Dan saya ingin mengekstrak file 10:26 bagiannya.

Ada yang tahu cara melakukan ini hanya dengan bash - tanpa menggunakan sed, awk, dll?

Seperti, di PHP saya akan menggunakan - bukan cara terbaik, tetapi berhasil - sesuatu seperti:

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

Terima kasih atas bantuan apa pun, meskipun jawabannya menggunakan sed atau awk

Jawaban:


207

Menggunakan murni :

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

solusi lain dengan bash regex:

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

solusi lain menggunakan grepdan melihat-lihat regex lanjutan:

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

solusi lain menggunakan sed:

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

solusi lain menggunakan perl:

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

dan yang terakhir menggunakan awk:

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

Keren! Adakah kemungkinan saya juga menggunakan tanda hubung "-" dalam pola? karena grep itu mengembalikan beberapa kecocokan, dan saya hanya tertarik pada yang memiliki tanda hubung lalu spasi dan kemudian waktu .....
andrux

Saya mungkin bisa mendapatkan solusi perl, tetapi ini adalah nilai tambah yang luar biasa. Terima kasih!
andrux

menambahkan satu awk untuk bersenang-senang =)
Gilles Quenot

1
Terima kasih telah memberi tahu saya \ K "trik". grep dengan sintaks perl benar-benar ampuh.
Marco Sulla

1
Saya suka sedversinya tetapi ingin memperingatkan orang lain bahwa sedtidak perlu menggunakan +pengubah. Salah satu cara untuk menyiasatinya adalah dengan menggunakan {1, }pengubah untuk mencocokkan satu atau lebih.
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
Saya merasa seperti ini membuat saya menjadi master sed instan. Satu opsi bagus yang bisa saya atur lebih baik dari sembilan, saya tidak mengerti.
Noumenon

Terima kasih atas penjelasan mendetailnya, membantu menghindari postingan "bagaimana cara regexp XXXX" di masa mendatang.
studgeek

4
Bisakah Anda menjelaskan mengapa Anda pertama kali menyembunyikan pencetakan dengan -nkemudian meminta pencetakan lagi /p? Bukankah sama saja dengan menghilangkan -nflag dan menghilangkan /pperintah? Terima kasih.
Victor Zamanian

Jawaban yang bagus! Terima kasih atas bantuan Anda :-)
Bruno Lavit

1
@VictorZamanian dari sini : "Secara default, sed mencetak setiap baris. Jika itu membuat substitusi, teks baru yang dicetak, bukan yang lama. Jika Anda menggunakan argumen opsional untuk sed," sed -n, "itu tidak akan, secara default, cetak baris baru. ... Jika opsi "-n" digunakan, tanda "p" akan menyebabkan baris yang dimodifikasi dicetak. "
tdashroy

26

Teknik chop-chop yang cepat dan kotor, bebas regex, dengan kekokohan rendah

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

5
Itu sangat kotor sehingga aku malu karena tidak memikirkannya sendiri. +1 | read zone dash time apm zonejuga berfungsi
Orwellophile

Sangat bersih, dan menghindari panggilan ke program eksternal.
Victor Zamanian

8
Hai, ini akan menjadi 10x lebih berguna jika menyertakan referensi untuk dokumentasi lebih lanjut atau beberapa nama seputar teknik sehingga orang dapat pergi dan meneliti lebih lanjut. Bagi yang tertarik, ini adalah manipulasi string bash, dan Anda dapat menemukan detail lebih lanjut di sini: tldp.org/LDP/abs/html/string-manipulation.html
Pedro Mata-Mouros

0

Jika string Anda

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

kemudian

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

akan melakukan pekerjaan itu.


1
atau cut -c14-18tentu saja selama posisi karakter tidak berubah. yang seharusnya tidak terjadi jika Zona Waktu diperbaiki.
Markus

Pak pertanyaan diminta untuk regex bukan untuk cut
indrajit narvekar
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.