在纯bash中使用regexp提取子字符串


97

我正在尝试使用bash从字符串中提取时间,并且很难弄清楚时间。

我的字符串是这样的:

US/Central - 10:26 PM (CST)

我想提取10:26一部分。

有人知道仅使用bash可以执行此操作的方法-不使用sed,awk等吗?

就像,在PHP中,我将使用-不是最好的方法,但它可以正常工作-类似:

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

感谢您的帮助,即使答案使用sed或awk

Answers:


207

使用纯

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

bash regex的另一个解决方案:

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

使用grep和环视高级正则表达式的另一种解决方案:

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

使用sed的另一种解决方案:

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

使用perl的另一种解决方案:

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

最后一个使用awk:

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

凉!是否有可能在模式中也使用连字符“-”?因为该grep返回了一些匹配项,所以我只对具有连字符,空格和时间的
那个感兴趣

我本来可以得到perl解决方案,但这是一个很好的加分。谢谢!
andrux 2012年

为乐趣添加了awk一个=)
Gilles Quenot 2012年

1
谢谢您让我知道\ K“技巧”。具有perl语法的grep确实功能强大。
Marco Sulla 2014年

1
我喜欢该sed版本,但想警告其他sed未必带有+修饰符的人。解决方法之一是使用{1, }修饰符来匹配一个或多个。
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
我觉得这使我立即成为sed大师。我可以调整的一个好选择胜过我不了解的九个。
Noumenon

感谢您的详细解释,有助于避免将来出现“我如何对XXXX进行正则表达式”的帖子。
studgeek

4
您能解释一下为什么先禁止打印-n然后再请求打印/p吗?省略-n标志和省略/p指令不是一样吗?谢谢。
Victor Zamanian '17

好答案!感谢您的帮助:-)
Bruno Lavit

1
@VictorZamanian来自这里:“在默认情况下,每行的sed打印如果换人,新的文本打印,而不是旧如果使用可选参数sed的。‘sed的-n,’不会,默认情况下,打印所有新行。...当使用“ -n”选项时,“ p”标志将导致修改后的行被打印。“
tdashroy19年

26

快速'n脏,无正则表达式,低健壮的印章技巧

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

5
那真是令人作呕的肮脏,以至于我为自己没想到而感到羞耻。+1也| read zone dash time apm zone起作用
Orwellophile

非常干净,并且避免了对外部程序的调用。
维克多·扎马尼亚

8
嗨,如果它包含对其他文档的引用或该技术的一些名称,这样人们将可以进行更多的研究,那么它将有用10倍。对于感兴趣的人,这是bash字符串操作,您可以在这里找到更多详细信息:tldp.org/LDP/abs/html/string-manipulation.html
Pedro Mata-Mouros

0

如果你的字符串是

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

然后

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

会做的工作。


1
或者cut -c14-18当然只要字符位置没有变化即可。如果时区固定,则不应发生这种情况。
马库斯

先生问的问题是要不要使用正则表达式
indrajit narvekar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.