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

在普通bash中使用regexp提取子字符串,regex,bash,Regex,Bash,我试图使用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或aw

我试图使用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

另一个解决方案是使用
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}}}'
$echo“美国/中部-晚上10:26(中央标准时间)”|

awk'{for(i=0;iQuick'n肮脏、无正则表达式、低健壮性的切碎技术

string="US/Central - 10:26 PM (CST)"
etime="${string% [AP]M*}"
etime="${etime#* - }"
如果你的字符串是

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


我会做的。

酷!我有没有可能在模式中也使用连字符“-”呢?因为grep会返回一些匹配项,而我只对带有连字符、空格和时间的匹配项感兴趣……我可能已经得到了perl解决方案,但这是一个极好的加号。谢谢!谢谢你让我知道\K“诀窍”.grep和perl语法非常强大。我喜欢
sed
版本,但想提醒其他人
sed
不一定需要
+
修饰符。解决问题的一种方法是使用
{1,}
修改器以匹配一个或多个。这太脏了,我很惭愧自己没有想到它。+1
| read zone dash time apm zone
工作非常干净,避免调用外部程序。嗨,如果它包括对进一步文档的参考或有关该技术的一些名称,这将是10倍有用,以便人们可以进行更多的研究。对于感兴趣的人,这是bash字符串操作,您可以在这里找到更多细节:我觉得这让我成为了即时sed大师。我可以调整的一个好选项比我不理解的九个好。感谢详细的解释,这有助于避免未来的“我如何regexp XXXX”帖子。你能解释一下为什么你先用
-n
禁止打印,然后再请求用
/p
再次打印吗?省略
-n
标志和省略
/p
指令不是一样吗?谢谢。回答得很好!谢谢你的帮助:-)@VictorZamanian from:“默认情况下,sed打印每一行。如果它进行替换,则打印新文本而不是旧文本。如果使用sed的可选参数“sed-n”,则默认情况下,它不会打印任何新行……当使用“-n”选项时,“p”标志将导致打印修改后的行。”。“或者
cut-c14-18
当然,只要字符位置没有改变。如果时区是固定的,就不会发生这种情况。先生,问题是针对regex而不是针对cut
string="US/Central - 10:26 PM (CST)"
etime="${string% [AP]M*}"
etime="${etime#* - }"
    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
foo="US/Central - 10:26 PM (CST)"
echo "${foo}" | cut -d ' ' -f3