行的开头或中间的模式的Grep


9

我首先要说的是,我认为这个问题比听起来听起来要简单得多。

我需要做的是:检查PATH环境变量中的文件夹。可能在开始时或之后。我只需要验证该文件夹在那里。

我的问题的例子-让我们使用/opt/gnome


场景1:文件夹不在PATH的开头

# echo "$PATH"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

# echo "$PATH" | grep ":/opt/gnome"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

请注意,grep必须足够具体,以使其不会被捕获/var/opt/gnome。因此冒号。


场景2:文件夹位于PATH的开头。

# echo "$PATH"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

# echo "$PATH" | grep "^/opt/gnome"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

这是我的问题-我需要使用此文件夹搜索冒号或行首。我想做的是以下两个括号表达式之一:

# echo $PATH | grep "[^:]/opt/gnome"
# echo $PATH | grep "[:^]/opt/gnome"

但是[^[:有自己的含义。因此,以上两个命令不起作用。

有没有一种方法可以在一个命令中针对这两种情况进行grep?


请注意,吉尔斯(Gilles)对Costas答案的评论也适用于该问题:由于您没有为/opt/gnome:或拼写/opt/gnome$,您将找到/opt/gnome-foo/opt/gnome/bar
斯科特

@Scott-只要您在比赛中包括中间空格,就可以始终将任何字符串锚定到该行的头和尾,而不会带来任何复杂性。就像grep '^\(any number of other matches:*:\)*my match\(:.*\)*$'
mikeserv

Answers:


10

如果要检查PATH环境变量的内容,而不是在文件中查找内容,那么这grep是错误的工具。在shell中执行此操作更容易(并且更快,并且更具可读性)。

在bash,ksh和zsh中:

if [[ :$PATH: = *:/opt/gnome:* ]]; then
 : # already there
else
  PATH=$PATH:/opt/gnome
fi

便携性:

case :$PATH: in
  *:/opt/gnome:*) :;; # already there
  *) PATH=$PATH:/opt/gnome;;
esac

注意使用:$PATH:而不是$PATH; 这样,即使该组件位于的开头或结尾,该组件也始终在搜索字符串中被冒号包围$PATH

如果您要搜索文件的某一行,则可以使用扩展的regexp(即require grep -E(^|:)/opt/gnome($|:)进行匹配,/opt/gnome但前提是该行位于行的开头或冒号之后,并且只能位于行或冒号。


8

您可以只使用扩展正则表达式 grep -E

如果要避免误报,则必须匹配要尝试找到的路径的开始和结尾。

在开始时匹配实例:

$ TEST=/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

也匹配中间的实例:

$ TEST=/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

避免误报:

$ TEST="/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta"
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"

那里没有比赛。

紧凑而优雅。在Debian 7上测试。


1
egrep已弃用使用grep -E(来源:man grep
安森

谢谢,作品就像一个魅力!我没有选择它作为答案,因为我认为-w选项稍微简单一些。比我原来想象的还要简单!
JamesL 2014年

3
警告。该-w选项有一些问题。仅将数字,字母和下划线视为“单词”。因此,一些异常但可能的字符会使它失败。示例echo '/sbin:/usr/sbin:/var-/opt/gnome' | grep -w "/opt/gnome"echo '/sbin:/usr/sbin:/var./opt/gnome' | grep -w "/opt/gnome"。那些提供错误的结果。
路易斯ANTOLIN卡诺

1
您的路线正确,但仍然存在误报:/opt/gnome/somethingelse
吉尔斯(Gillles)“所以-别再作恶了”

1
完全正确。我们应该明确地关注结局,而不仅仅是开始。我认为这可以解决问题echo "/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta" | grep -E "(:|^)/opt/gnome(:|$)"。编辑答案。
LuisAntolínCano 2014年

7

如果您不愿意grep,可以在以下位置使用awk和分离记录:

awk 'BEGIN {RS=":"} /^\/opt\/gnome$/'

5

您也可以使用

echo "$PATH" | tr ':' '\n' | grep -x "/opt/gnome"

它将路径变量分成单独的行(每条路径一个),因此grep -x可以寻找确切的结果。当然,这有一个缺点,那就是它需要一个额外的过程tr。当文件夹名称中PATH包含换行符时,它将不起作用。


2

我不知道是否足够回答

grep -w "/opt/gnome"

将满足您的需求。

echo '/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome
echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome

echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep "/opt/gnome" -o
/opt/gnome
/opt/gnome

由于冒号是非单词字符,因此可以完美地工作。谢谢!
JamesL 2014年

@ Sman865还有另一个原因:因为/不是单词的一部分,而是单词的一部分r
Costas 2014年

2
警告。正如我在回答我的评论时所说的。目录名称的合法字符为非单词字符。这导致错误的结果。通常不以-结尾目录名,但是可能会发生。
LuisAntolínCano 2014年

4
@ Sman865误报:/opt/gnome-beta/home/bob/opt/gnome,...
吉尔'SO-停止作恶'

不起作用的情况:grep -w /usr/local -o <<< /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games------/usr/local /usr/local /usr/local
pabouk

0

要选择/opt/gnome非单词字符包围(新线,:/,等)试试这个:

grep '\B/opt/gnome'

0

您可以轻松可靠地做到这一点grep。您可以利用广泛使用的扩展功能,并且已经从中提供了许多解决方案,但是即使使用基本的正则表达式也可以轻松实现,尽管乍一看可能并不直观。

使用基本的正则表达式-等等grep-您总是会有两个可靠的锚点-行的头和尾。您可以将匹配项固定到这两个匹配项上,而不管其在行中的位置,例如:

grep '^\(ignore case, delimiter\)*match\(delimiter, ignore case\)*$'

grep从该行的开头匹配\(grouped\)次要出现的子表达式的次数,直到遇到下一个定界符然后是您的显式匹配为止,然后以相同的方式从匹配的结尾到该行的结尾匹配。如果您的显式匹配项与式匹配项不匹配,它将失败并且不打印任何内容。

因此,您可以这样做,例如:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$'

你自己看:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$
' <<\INPUT
/opt/gnome-beta
/opt/gnome
/home/bob/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt-gnome-beta
/opt/gnomenot::::/opt/gnome
INPUT

输出值

/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt/gnomenot::::/opt/gnome

0

您已经注意到一种边缘情况...您可以通过在行的开头强制使用:来避免出现这种情况:

 echo ":$PATH" | grep ":/opt/gnome"

或者,如果路径是精确的,则在末尾也添加一个以确保它是有界的:

 echo ":${PATH}:" | grep ":/opt/gnome:"
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.