ls
显示:
entry1
entry2
entry3
如何在下一个 shell 命令中重用上述输出(不是所有条目,而是给定行的条目,例如 n)?
就像是:
vi $(!!)@3
必须意味着:
vi entry3
答案1
您不能直接重用输出:它仅作为一堆像素存储在视频内存中;或者可能在终端模拟器的内存中,但也没有方便的方法可以从那里取回它。您可以做的是再次运行该命令并捕获这次的输出。这就是作用!!
。
在 zsh 中,使用参数扩展标志和嵌套替换以提取所选行。或者,您可以让外部实用程序进行拆分,这样更容易键入。
vi "${${(f)$(!!)}[3]}"
vi "$(!! | awk NR==3)"
这是即使在 zsh 中也确实需要双引号的少数情况之一,否则命令的输出将被拆分为空格分隔的组件。如果空格分隔的组件没问题,那么您可以使用更短的命令:
vi ${$(!!)[3]}
答案2
从输出中提取特定行的经典方法是组合head
和tail
命令:
LINE=3
ls | head -n $LINE | tail -n 1
ls
命令生成初始输出,head -n $LINE
$LINE
仅保留原始输出的第一行,tail -n 1
仅保留命令输出的最后一行head
。
最后,仅保留给定位置处的线。
因此,为了继续您的示例,假设此输出包含您需要使用 编辑的文件的名称vi
,您可以通过以下语法使用此输出:
vi $(ls | head -n $LINE | tail -n 1)
vi `ls | head -n $LINE | tail -n 1`
由于其可读性,第一个是首选。第二个是与旧系统兼容的历史版本。
最后要注意的是,有时初始命令(ls
本例中为简单命令)可能需要时间并消耗资源来执行。如果您需要从其输出中获取几行,请毫不犹豫地将其输出存储在变量或文件中,这样它只需执行一次:
# Using a variable:
my_ls=$(ls)
vi $(echo "$my_ls" | head -n 3 | tail -n 1)
vi $(echo "$my_ls" | head -n 26 | tail -n 1)
vi $(echo "$my_ls" | head -n 1900 | tail -n 1)
# Using a file:
ls >./my_ls
vi $(cat ./my_ls | head -n 3 | tail -n 1)
vi $(cat ./my_ls | head -n 26 | tail -n 1)
vi $(cat ./my_ls | head -n 1900 | tail -n 1)
答案3
我对 zsh 没有太多经验,但一种可能的方法可能是这样的:
$ p() { i=$1 && shift && a=("${(@f)$("$@")}") && echo "${a[$i]}" }
$ ls
entry1
entry2
entry3
$ echo $(p 3 !!)
echo $(p 3 ls)
entry3
对于bash:
$ p() { i=$1 && shift && IFS=$'\n' a=($("$@")) && echo "${a[$((i-1))]}"; }
我承认这是相当麻烦的语法并且没有错误检查。