如何使用grep输出作为cd的路径?


9

如何通过管道将grep输出作为cd命令的参数?

例如:

[root@xxx xxx]# pip install django | grep '/usr.*'  
Requirement already satisfied (use --upgrade to upgrade): django in   /usr/lib64/python2.7/site-packages

这里/usr/lib64/python2.7/site-packages突出显示,我想将此字符串传递给cd

Answers:


16

使用Bash的命令替换 $(),您还需要-o使用grep仅选择匹配的部分:

cd "$(pip install django | grep -o '/usr.*')"

请注意,尽管在这种情况下您会逃脱,但是您应该始终用双引号将命令替换括起来,以使外壳程序不对空格执行单词拆分(默认情况下,空格,制表符和换行符取决于IFS情况下的变量bash)。


9

根据您所做的事情和事先不知道pip将输出的内容,您可能会决定使用grep而不是/usr.*

如果您知道目录以/usr以开头,并且出现在的输出行的末尾pip,并且/usr未出现在目录名之前的行的任何地方),那么这是一个不错的选择;heemayl的答案告诉您如何。

如果您知道它开始的原因/usr是您刚刚运行了命令并知道了要更改的目录,那么建议您使用运行命令的更简单的解决方案cd /usr/lib64/python2.7/site-packages。即使您不使用制表符补全,也可以减少打字。

否则,您可以根据对所解析的输出的了解来选择其他正则表达式。下面的所有替代方案仍假定目录名称显示在该行的末尾,但其他假设有所不同。

如果您知道目录名称是绝对的(即以开头/),并且/目录名称之前的行中没有出现,则可以使用与heemayl的答案相同的regexp,但可以使用/代替/usr

cd "$(pip install django | grep -o '/.*')"

这与/后跟零个或多个(*)的任何字符(.)相匹配。

如果您知道目录名不包含水平空格(没有空格或制表符)并且出现在行的末尾,则可以使用:

cd "$(pip install django | grep -oP '[^\h]+$')"

在这里,我使用了Perl regexp-P),因为\h缩写(for [:blank:])使它的输入和阅读比等效的扩展regexp(-E)更容易。这会与()空格或制表符()的+一类字符([ ])中的任何一个或多个字符()相匹配。^\h

如果您知道目录名前面紧跟in着水平空白(即在左右两侧都用空格填充),并且这是该行中唯一的这种情况,in可以使用:

cd "$(pip install django | grep -oP '\hin\h+\K.+')"

它使用零宽度正向后断言(\K)来匹配.+在空格或制表符(\h)之后出现的一个或多个字符()in和另一个或多个空格或制表符(\h+)之后出现的字符,而不实际包含in和空格在比赛中将其包围。环顾断言是Perl正则表达式的功能。

该模式也可以使用,但是无论存在多少,我们都只需要在前面查找一个空格即可。相反,我们必须匹配之后的所有空格,否则它们将不会被丢弃,并且会作为目录名称的一部分进行匹配。\h+in\h+\K.+inin\K

如果您知道目录名紧跟在行的最后一次出现之后,in然后是水平空格,则可以使用:

set +H
cd "$(pip install django | grep -oP '\hin\h+(?!.*\hin\h.*)\K.*')"
set -H

在这里,零宽度的正向后断言本身包含一个零宽度的负向前断言((?! ))。

!以这样的方式为可出现难以逃脱优雅; 我用来阻止它在传递给它之前触发外壳程序历史记录扩展的方法grepset +H在运行命令之前暂时禁用历史记录扩展(),然后重新启用它(set -H)。如果您在脚本中使用此脚本,而您的脚本中不包含set -H,则不需要这样做,因为仅当shell交互式运行时,历史记录扩展才会自动启用。

最后,需要注意的是没有这些,也不heemayl的回答,实际上是管道输出grepcd(虽然输出pip仍然被输送到grep)。而不是管道,这份工作的合适的工具是命令替换


当然,如果您想获得技术性知识,shell会在内部使用管道来读取命令输出。
Random832'2015-4-24

@ Random832好点-考虑到这一点,我进行了一些编辑。顺便说一句,您知道是否可以依靠在命令替换中使用“后台”管道?还是在不同的bash未来版本中可能会以不同方式完成的实现细节?(当然,在实践中,我知道这是最好的方法,因此不太可能以其他方式实施。)
Eliah Kagan

1
不,不能保证,从理论上讲,shell可以使用命名的fifo或temp文件,尽管没有理由。
Random832'2015-4-24

您确定历史扩展吗?唯一可以阻止它的字符是` and ``,并且您在grep表达式周围使用了单引号。
muru

1
@muru 是的,它已经扩展了。我也没有注意到,但是在测试时发现了。其中!没有用-引号'引起来,因为- '引号本身也是用引号引起的。该命令的复杂性使其很容易错误地预测其效果,但是显然由于扩展顺序(!较早),它最终的工作方式类似于x=foo; echo "'$x'"(-> 'foo')。除去外部"引号将导致!'引号并阻止历史记录扩展,但是cd 如果目录名称中包含空格,则失败。
Eliah Kagan 2015年
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.