我创建了一个别名,以便每次进入新目录时都不写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中执行命令,同时将输出重定向到另一个命令。
答案 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可用。