在普通bash中使用正则表达式提取子字符串

Posted

技术标签:

【中文标题】在普通bash中使用正则表达式提取子字符串【英文标题】:Extract substring using regexp in plain bash 【发布时间】:2012-11-02 14:52:58 【问题描述】:

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

我的字符串是这样的:

US/Central - 10:26 PM (CST)

我想提取10:26 部分。

任何人都知道只使用 bash 来执行此操作的方法 - 不使用 sed、awk 等?

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

preg_match( ""(\d2\:\d2) PM \(CST\)"", "US/Central - 10:26 PM (CST)", $matches );

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

【问题讨论】:

【参考方案1】:

使用纯bash:

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

另一种使用 bash 正则表达式的解决方案:

$ [[ "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\d2:\d2"

另一种使用 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\d2:\d2/'

最后一个使用 awk :

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

【讨论】:

酷!我有没有机会在模式中也使用连字符“-”?因为该 grep 返回一些匹配项,而我只对具有连字符、空格和时间的匹配项感兴趣..... 我可能已经得到了 perl 解决方案,但这是一个很好的加分项。谢谢! 感谢您让我知道 \K “技巧”。 grep 加上 perl 语法真的很强大。 我喜欢sed 版本,但想警告其他人sed 不一定采用+ 修饰符。一种解决方法是使用1, 修饰符来匹配一个或多个。【参考方案2】:
    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

【讨论】:

我觉得这让我成为了一个即时的 sed 大师。我可以调整的一个好选择比我不理解的九个要好。 感谢您的详细解释,有助于避免将来出现“我如何正则表达式 XXXX”的帖子。 您能解释一下为什么您先用-n 禁止打印,然后再用/p 请求打印吗?省略-n 标志和省略/p 指令不是一样吗?谢谢。 很好的答案!感谢您的帮助:-) @VictorZamanian from here: "默认情况下,sed 打印每一行。如果它进行替换,则打印新文本而不是旧文本。如果您使用 sed 的可选参数, “sed -n”,默认情况下不会打印任何新行。...当使用“-n”选项时,“p”标志将导致打印修改的行。”【参考方案3】:

Quick 'n dirty、无正则表达式、低鲁棒性的斩波技术

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

【讨论】:

这太恶心了,我很惭愧我自己没有想到。 +1 | read zone dash time apm zone 也可以 非常干净,避免调用外部程序。 嗨,如果它包含对进一步文档的引用或围绕该技术的一些名称的引用,那么这将是有用的 10 倍,以便人们可以进行更多研究。对于感兴趣的,这是 bash 字符串操作,您可以在此处找到更多详细信息:tldp.org/LDP/abs/html/string-manipulation.html【参考方案4】:

如果你的字符串是

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

然后

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

会做的。

【讨论】:

cut -c14-18 当然只有在字符位置不变的情况下。如果时区是固定的,这不应该发生。 向先生询问正则表达式而不是剪切【参考方案5】:

foo="美国/中部 - 晚上 10:26 (CST)"

回声 $foo |日期 +%H:%M

【讨论】:

您好 Jimbro,欢迎来到 ***!不幸的是,这不是问题的解决方案。请注意,OP 希望从字符串中提取日期,您的解决方案返回当前日期。

以上是关于在普通bash中使用正则表达式提取子字符串的主要内容,如果未能解决你的问题,请参考以下文章

bash shell中字符串匹配正则表达式的子字符串[重复]

正则表达式从bash脚本中的字符串中提取第一个浮点数

C++ 正则表达式提取子字符串

使用正则表达式从 mysql 列中提取子字符串

Java使用正则表达式提取字段分隔的子字符串

使用正则表达式从 Ruby 中的字符串中提取子字符串