cd&& ls | grep:如何在当前shell中执行命令并传递输出

时间:2016-06-28 11:22:58

标签: linux bash unix

我创建了一个别名,以便每次进入新目录时都不写ls:

alias cl='cd_(){ cd "$@" && ls; }; cd_'

我们假设我有一个名为"下载"的文件夹。 (当然我碰巧有)所以我只需在终端输入以下内容:

cl Downloads

现在我将发现自己处于"下载"文件夹,并收到我在文件夹中的东西列表,如:example.txt,hack.hs,picture.jpg,...

如果我想移动到一个目录并查看是否有hack.hs我可以尝试这样的事情:

cl Downloads | grep hack

我得到的只是输出:

hack.hs

但我会留在我的文件夹中(这意味着我不在下载中)。

我明白这是因为每个命令都在子shell中执行,因此cd Downloads&& ls在它自己的子shell中执行,然后输出(即我拥有的东西列表)通过管道重定向到grep。这就是我不在新文件夹中的原因。

我的问题如下:

我该怎么做才能写出类似" cl下载|的东西grep hack"并获取" hack" -greped列表的内容并在Downloads文件夹中?

非常感谢, POL

对于任何用Google搜索过的人: @gniourf_gniourf提出快速修复

cl Downloads > >(grep hack)

有些人将此问题标记为Make bash alias that takes duplicates的可能副本,但我的bash别名已经采用参数的事实表明情况并非如此。手头的问题是如何在当前shell中执行命令,同时将输出重定向到另一个命令。

1 个答案:

答案 0 :(得分:2)

正如您所知(并且正如BashFAQ #24所述),原因

{ cd "$@" && ls; } | grep ...

...防止cd在外壳中可见的结果是POSIX没有保证管道的任何组件在外壳中运行。 (有些shell,包括ksh [开箱即用]和非常现代的bash,启用了非默认选项),偶尔会或可选地运行父shell中的最后一个管道,但这不能依赖上)。

一种避免这种情况的方法,即适用于所有POSIX shell,是将输出定向到命名管道,从而避免设置管道:

mkfifo mypipe
grep ... <mypipe &
{ cd "$@" && ls; } >mypipe

在现代的ksh和bash中,有一个更短的语法可以为你做到这一点 - 如果操作系统提供了这个设施,则使用/dev/fd条目而不是设置命名管道:

{ cd "$@" && ls; } > >(grep ...)

在这种情况下,>(grep ...)将替换为指向FIFO或/dev/fd条目的文件名,当由相关进程写入时,将输出重定向到grep - 但没有管道。

顺便说一句 - 我真的希望以这种方式使用ls作为一个例子。对于所有可能的文件名范围,ls的输出没有明确规定,因此对其进行加权是天生不可靠的。如果您确实想要构建流式结果,请考虑使用printf '%s\0' *在目录中发出NUL分隔的非隐藏名称列表;或使用glob expressions检查与特定模式匹配的文件(BashFAQ #4涵盖类似的情况);如果您需要比POSIX模式支持更接近完整正则表达式匹配支持的内容,则extglobs可用。

相关问题