用sed和有条件地呈现白色空间提取文本

时间:2018-03-05 22:29:03

标签: bash sed freebsd

我正在尝试动态查找稍后在脚本中以编程方式使用的目录。我遇到的问题是考虑到可能存在或可能不存在的空白区域。

使用以下示例,因为它输出由空格分隔的三个字符串(在本例中为路径)。让我们假设我想使用whereis获取特定命令的手册页目录(暂时忘记有内置的方法):

$ whereis bash
bash: /bin/bash /usr/local/man/man1/bash.1.gz /usr/ports/shells/bash

我想提取任何一个目录。使用sed,我想出了以下内容:

$ whereis bash | sed -En 's:.*[" "](.*man.*)[" "].*:\1:p'
/usr/local/man/man1/bash.1.gz

如果模式恰好位于中间,那么效果很好,但如果恰好位于字符串的开头或结尾,我必须从模式中删除空格才能使其工作(使用" port" for the pattern as example)

$ whereis bash | sed -En 's:.*[" "](.*port.*)[" "].*:\1:p'

$ whereis bash | sed -En 's:.*[" "](.*port.*).*:\1:p'
/usr/ports/shells/bash

如果我想用模式" bin"提取目录,情况也是如此。在它。

我如何"告诉" {em>可能的模式sed包含某个字符。

我为什么要这样做?

当我尝试没有空格时,我得到以下内容:

$ whereis bash | sed -En 's:.*(.*man.*).*:\1:p'
man1/bash.1.gz /usr/ports/shells/bash

我没有获得我想要的文字的完整路径,它增加了我完全不想要的路径。这个空间是一个分隔符。

我使用过这篇文章:How to output only captured groups with sed?和帖子:sed - how to do regex groups using sed作为参考和跳跃点。

另外值得注意的是,我尝试将正则表达式\s用于空格,但它被忽略了。我也在FreeBSD上,所以我使用-E作为正则表达式。

如果还有另一种方法可以解决这个问题,那么我们将非常感谢正确方向上的一点。我非常擅长使用sedawk

2 个答案:

答案 0 :(得分:1)

sed可能不是此任务的正确工具。您可以使用以下内容迭代输出:

foreach f in `whereis bash` ; do
    echo $f | grep /man/
done

要解决具体的whereis问题,最好使用内置的FreeBSD选项以-b,-m和-s返回二进制,手册页或源。将它与-q(安静)选项结合使用,您就可以获得设计用于脚本的内容。所以:

 whereis -mq bash

将返回/usr/local/man/man1/bash.1.gz

如果你的用例是别的,你绝对必须使用sed,这应该给你想要的东西:

whereis bash | sed -E 's|^.*[[:space:]]+([^[:space:]]+man[^[:space:]]+).*$|\1|'

FreeBSD 11正则表达式符合IEEE Std 1003.2(POSIX.2),不支持\ s \ S表示法。因此,您需要使用[[:space:]]字符类。可以通过re_format(7)手册页找到更多信息。

答案 1 :(得分:0)

如果你想使用正则表达式,你需要考虑它们是"贪心" (*尝试尽可能匹配),所以你需要通过在表达式之前查找空格来限制它(可以用\ s完成)并且只在你看到非空格时继续表达式(可以完成\ S)。

所以这应该有效:

whereis bash | sed -En 's:.*\s(\S*man\S*).*:\1:p'

虽然我发现你可以在bash函数中更轻松地处理这个问题,在这种情况下你可以一次处理一个单词,你可以使用更简单的 globs 而不是正则表达式。

例如:

find_manpage() {
    local tool=$1
    local path
    set -- $(whereis "${tool}")
    for path ; do
        if [[ "${path}" == *man* ]] ; then
            echo "${path}"
            return 0
        fi
    done
    return 1
}

并使用它:

find_manpage bash

或者:

manpage_path=$(find_manpage bash)

您可以轻松扩展该功能以采用"模式"作为第二个参数并匹配它,使它更通用而不仅仅是找到联机帮助页。

我希望这有帮助!