bash - 自动将上次执行的命令的输出捕获到变量中

arm*_*ino 135 linux bash command-line

我希望能够在后续命令中使用上次执行的命令的结果.例如,

$ find . -name foo.txt
./home/user/some/directory/foo.txt
Run Code Online (Sandbox Code Playgroud)

现在让我们说我希望能够在编辑器中打开文件,或删除它,或者用它做其他事情,例如

mv <some-variable-that-contains-the-result> /some/new/location
Run Code Online (Sandbox Code Playgroud)

我该怎么做?也许使用一些bash变量?

更新:

为了澄清,我不想手动分配东西.我所追求的是内置的bash变量,例如

ls /tmp
cd $_
Run Code Online (Sandbox Code Playgroud)

$_保存上一个命令的最后一个参数.我想要类似的东西,但是使用最后一个命令的输出.

最后更新:

赛斯的答案非常有效.要牢记几件事:

  • 不要忘记touch /tmp/x第一次尝试解决方案时
  • 只有在上一个命令的退出代码成功时才会存​​储结果

Dae*_*yth 88

我不知道任何自动执行此操作的变量.除了复制粘贴结果之外还要做一些事情,你可以重新运行你刚刚做的任何事情,例如

vim $(!!)
Run Code Online (Sandbox Code Playgroud)

!!历史扩展在哪里意味着"前一个命令".

如果您希望单个文件名中包含空格或其他字符,可能会阻止正确的参数解析,请引用result(vim "$(!!)").只要它们不包含空格或其他shell解析标记,只要不加引号就允许一次打开多个文件.

  • 你可以用更少的键击来做同样的事情:`vim \`!! \`` (4认同)

Set*_*son 71

这是一个真正的hacky解决方案,但它似乎主要在某些时候工作.在测试过程中,我注意到^C在命令行上获取时有时效果不佳,但我确实调整了一下以表现得更好.

这个hack只是一个交互式模式hack,我相信我不会推荐给任何人.后台命令可能导致比正常情况更少定义的行为.其他答案是以编程方式获得结果的更好方法.


话虽如此,这里是"解决方案":

PROMPT_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)'
Run Code Online (Sandbox Code Playgroud)

设置此bash环境变量并根据需要发出命令. $LAST通常会有您正在寻找的输出:

startide seth> fortune
Courtship to marriage, as a very witty prologue to a very dull play.
                -- William Congreve
startide seth> echo "$LAST"
Courtship to marriage, as a very witty prologue to a very dull play.
                -- William Congreve
Run Code Online (Sandbox Code Playgroud)

  • @armandino:这当然会导致希望与标准输出终端交互的程序无法按预期工作(更多/更少)或在 $LAST (emacs) 中存储奇怪的东西。但我认为它和你得到的一样好。唯一的其他选择是使用(类型)脚本将所有内容的副本保存到文件中,然后使用 PROMPT_COMMAND 检查自上次 PROMPT_COMMAND 以来的更改。不过,这将包括您不想要的东西。不过,我很确定你不会找到更接近你想要的东西。 (2认同)
  • 更进一步:`PROMPT_COMMAND ='last ="$(cat/tmp/last)"; lasterr ="$(cat/tmp/lasterr)"; exec>/dev/tty; exec >>(tee/tmp/last); exec 2>/dev/tty; exec 2 >>(tee/tmp/lasterr)'`提供`$ last`和`$ lasterr`. (2认同)

rli*_*bby 20

Bash是一种丑陋的语言.是的,您可以将输出分配给变量

MY_VAR="$(find -name foo.txt)"
echo "$MY_VAR"
Run Code Online (Sandbox Code Playgroud)

但更好的希望你最难的find只返回一个结果,并且结果中没有任何"奇数"字符,如回车或换行,因为它们将在分配给Bash变量时被静默修改.

但是在使用它时最好小心引用你的变量!

最好直接对文件进行操作,例如使用find's -execdir(参考手册).

find -name foo.txt -execdir vim '{}' ';'
Run Code Online (Sandbox Code Playgroud)

要么

find -name foo.txt -execdir rename 's/\.txt$/.xml/' '{}' ';'
Run Code Online (Sandbox Code Playgroud)

  • 当你分配时,它们会被静默修改,当你_echo时它们被修改!_你只需要做`echo'$ {MY_VAR}"`就可以看到这种情况了. (5认同)

tas*_*oor 12

有多种方法可以做到这一点.一种方法是使用v=$(command)将命令输出分配给v.例如:

v=$(date)
echo $v
Run Code Online (Sandbox Code Playgroud)

你也可以使用反引号.

v=`date`
echo $v
Run Code Online (Sandbox Code Playgroud)

Bash初学者指南,

当使用旧式反引号替换形式时,反斜杠保留其字面含义,除非后跟"$","`"或"\".第一个没有反斜杠的反引号会终止命令替换.使用"$(COMMAND)"表格时,括号内的所有字符组成命令; 没有人特别对待.

编辑:在问题编辑后,似乎这不是OP正在寻找的东西.据我所知,没有像$_上一个命令的输出那样的特殊变量.


Wes*_*ker 11

这很容易.使用反引号:

var=`find . -name foo.txt`
Run Code Online (Sandbox Code Playgroud)

然后你可以在将来的任何时候使用它

echo $var
mv $var /somewhere
Run Code Online (Sandbox Code Playgroud)


小智 9

我想你可能会破解一个涉及将shell设置为包含以下内容的脚本的解决方案:

#!/bin/sh
bash | tee /var/log/bash.out.log
Run Code Online (Sandbox Code Playgroud)

然后,如果设置$PROMPT_COMMAND为输出分隔符,则可以编写一个辅助函数(可能称为_),它可以获取该日志的最后一个块,因此您可以使用它:

% find lots*of*files
...
% echo "$(_)"
... # same output, but doesn't run the command again
Run Code Online (Sandbox Code Playgroud)


Wie*_*err 9

Disclamers:

  • 这个答案是半年后期:D
  • 我是一个沉重的tmux用户
  • 你必须在tmux中运行你的shell才能工作

在tmux中运行交互式shell时,您可以轻松访问终端上当前显示的数据.我们来看看一些有趣的命令:

  • tmux capture-pane:这个将显示的数据复制到tmux的一个内部缓冲区.它可以复制当前不可见的历史记录,但我们现在对此不感兴趣
  • tmux list-buffers:显示有关捕获的缓冲区的信息.最新的将具有数字0.
  • tmux show-buffer -b(buffer num):这将打印终端上给定缓冲区的内容
  • tmux paste-buffer -b(buffer num):这会粘贴给定缓冲区的内容作为输入

是的,这给了我们很多可能性:)至于我,我设置了一个简单的别名:alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1"现在每次我需要访问最后一行时我只是用$(L)它来获取它.

这与程序使用的输出流(stdin或stderr),打印方法(ncurses等)和程序的退出代码无关 - 只需要显示数据.


小智 7

您可以在bash配置文件中设置以下别名:

alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))'
Run Code Online (Sandbox Code Playgroud)

然后,通过在任意命令后键入"s",可以将结果保存到shell变量"it".

所以示例用法是:

$ which python
/usr/bin/python
$ s
$ file $it
/usr/bin/python: symbolic link to `python2.6'
Run Code Online (Sandbox Code Playgroud)


Til*_*gel 6

我刚从bash这里的建议中提炼出这个函数:

grab() {     
  grab=$("$@")
  echo $grab
}
Run Code Online (Sandbox Code Playgroud)

然后,你只需:

> grab date
Do 16. Feb 13:05:04 CET 2012
> echo $grab
Do 16. Feb 13:05:04 CET 2012
Run Code Online (Sandbox Code Playgroud)

更新:匿名用户建议,以取代echoprintf '%s\n'具有它不处理类似的选项优势-e在抓住文本.因此,如果您期望或遇到这样的特点,请考虑这个建议.另一种选择是使用cat <<<$grab.


ban*_*ndi 5

使用反引号捕获输出:

output=`program arguments`
echo $output
emacs $output
Run Code Online (Sandbox Code Playgroud)


ssa*_*ota 5

通过说“我希望能够在后续命令中使用最后执行的命令的结果”,我假设-您的意思是任何命令的结果,而不仅仅是查找。

如果是这样的话-xargs是您想要的。

find . -name foo.txt -print0 | xargs -0 -I{} mv {} /some/new/location/{}

或者,如果您有兴趣先看到输出:

find . -name foo.txt -print0

!! | xargs -0 -I{} mv {} /some/new/location/{}

即使路径和/或文件名包含空格,此命令也可以处理多个文件,并且像超级按钮一样工作。

注意命令的mv {} / some / new / location / {}部分。对于先前命令打印的每一行,都会构建并执行此命令。在此,由先前命令打印的行替换为{}

xargs手册页的节选:

xargs-从标准输入构建和执行命令行

有关更多详细信息,请参见手册页: man xargs