bash – 自动捕获最后执行的命令的输出到一个variables中
我希望能够在后续的命令中使用最后执行的命令的结果。 例如,
$ find . -name foo.txt ./home/user/some/directory/foo.txt
现在让我们说,我想能够在编辑器中打开文件,或删除它,或者做一些其他的事情,例如
mv <some-variable-that-contains-the-result> /some/new/location
我该怎么做? 也许使用一些bashvariables?
更新:
为了澄清,我不想手动分配的东西。 我所追求的就像内置的bashvariables,例如
ls /tmp cd $_
$_
保存了前一个命令的最后一个参数。 我想要类似的东西,但最后一个命令的输出。
最终更新:
塞思的回答工作得很好。 记住几件事情:
- 当第一次尝试解决scheme时,请不要忘记
touch /tmp/x
- 只有当最后一个命令的退出代码成功时才会存储结果
这是一个非常糟糕的解决scheme,但似乎大部分时间都在工作。 在testing过程中,我注意到在命令行上获取^ C时,它有时效果不佳,尽pipe我稍微调整了一下以performance得更好一些。
这种黑客攻击只是一种交互模式,我相当自信,我不会推荐给任何人。 后台命令可能会导致比正常情况下更less的定义行为。 其他答案是以编程方式获得结果的更好方法。
这就是说,这里是“解决scheme”:
PROMPT_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)'
设置这个bash环境variables并根据需要发出命令。 $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
我不知道任何自动执行此操作的variables。 除了复制粘贴结果之外,你可以重新运行你刚刚做的任何事情,例如
vim $(!!)
哪里!!
是历史扩张,意思是“以前的命令”。
如果你希望有一个空格或其他字符的文件名,可能会阻止正确的参数parsing,请引用结果( vim "$(!!)"
)。 如果不加引号,只要不包含空格或其他shellparsing令牌,就可以一次打开多个文件。
Bash是一种丑陋的语言。 是的,您可以将输出分配给variables
MY_VAR="$(find -name foo.txt)" echo "$MY_VAR"
但希望你最难 find
只返回一个结果,并且结果中没有任何“奇怪的”字符,如回车或换行符,因为它们将被分配给Bashvariables时被无声修改。
但是更好地使用它时要小心地引用你的variables!
最好直接对文件进行操作,例如使用find
的-execdir
(参考手册)。
find -name foo.txt -execdir vim '{}' ';'
要么
find -name foo.txt -execdir rename 's/\.txt$/.xml/' '{}' ';'
有多种方法可以做到这一点。 一种方法是使用v=$(command)
将命令的输出分配给v
。 例如:
v=$(date) echo $v
你也可以使用反引号。
v=`date` echo $v
从Bash初学者指南 ,
当使用旧式反向引用的replaceforms时,除了后面跟有“$”,“`”或“\”之外,反斜杠将保留其字面含义。 第一个反斜杠前面没有反斜杠会终止命令replace。 当使用“$(COMMAND)”forms时,括号之间的所有字符组成命令; 没有一个是专门处理的
编辑:在问题的编辑后,似乎这不是OP所寻找的东西。 据我所知,最后一个命令的输出没有像$_
这样的特殊variables。
这很容易。 使用反引号:
var=`find . -name foo.txt`
然后你可以在将来的任何时候使用它
echo $var mv $var /somewhere
我想你可能能够破解一个解决scheme,涉及到设置你的shell脚本包含:
#!/bin/sh bash | tee /var/log/bash.out.log
那么如果你设置$PROMPT_COMMAND
来输出一个分隔符,你可以编写一个辅助函数(也许称为_
)来获取这个日志的最后一个块,所以你可以像这样使用它:
% find lots*of*files ... % echo "$(_)" ... # same output, but doesn't run the command again
Disclamers:
- 答案是半年后的:D
- 我是一个沉重的tmux用户
- 你必须在tmux中运行你的shell才能工作
在tmux中运行交互式shell时,可以轻松访问terminal当前显示的数据。 让我们来看看一些有趣的命令:
- tmux capture-pane :这个复制显示的数据到一个tmux的内部缓冲区。 它可以复制当前不可见的历史logging,但现在我们对此不感兴趣
- tmux list-buffers :显示关于捕获的缓冲区的信息。 最新的将有数字0。
- tmux show-buffer -b(缓冲区号) :打印terminal上给定缓冲区的内容
- tmux粘贴缓冲区-b(缓冲区号) :这将粘贴给定缓冲区的内容作为input
是的,这给了我们很多可能:)现在,我设置了一个简单的别名: alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1"
现在每次我需要访问最后一行时,只需使用$(L)
即可获得它。
这与程序使用的输出stream(stdin或stderr),打印方法(ncurses等)以及程序的退出代码无关 – 只需要显示数据。
你可以在你的bashconfiguration文件中设置以下别名:
alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))'
然后,通过在任意命令后input“s”,可以将结果保存到一个shellvariables“it”中。
所以示例用法是:
$ which python /usr/bin/python $ s $ file $it /usr/bin/python: symbolic link to `python2.6'
我只是从这里的build议中提炼出这个bash
函数:
grab() { grab=$("$@") echo $grab }
那么,你只是做:
> grab date Do 16. Feb 13:05:04 CET 2012 > echo $grab Do 16. Feb 13:05:04 CET 2012
更新 :一个匿名用户build议用printf '%s\n'
来代替echo
,这个优点是它不会处理抓取文本中的-e
选项。 所以,如果你期望或遇到这样的特点,请考虑这个build议。 另一个select是使用cat <<<$grab
代替。
我通常做这里的其他人所build议的……没有作业:
$find . -iname '*.cpp' -print ./foo.cpp ./bar.cpp $vi `!!` 2 files to edit
如果你喜欢,你可以更喜欢:
$grep -R "some variable" * | grep -v tags ./foo/bar/xxx ./bar/foo/yyy $vi `!!`
通过说“我希望能够在后续命令中使用最后执行的命令的结果”, 我假设 – 你的意思是任何命令的结果,而不仅仅是查找。
如果是这样的话 – 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/{}
这个命令处理多个文件,就像一个魅力,即使path和/或文件名包含空间(S)。
注意命令的mv {} / some / new / location / {}部分。 这个命令是为早期命令打印的每一行构build和执行的。 这里由前面的命令打印的行被replace为{} 。
摘自xargs手册页:
xargs – 从标准input构build和执行命令行
有关更多详细信息,请参见手册页: man xargs
用反引号捕获输出:
output=`program arguments` echo $output emacs $output
如果你想要的是重新运行你的最后一个命令并获得输出,一个简单的bashvariables可以工作:
LAST=`!!`
那么你可以在输出上运行你的命令:
yourCommand $LAST
这将产生一个新的过程,并重新运行你的命令,然后给你输出。 这听起来像你真正想要的是命令输出的bash历史文件。 这意味着您将需要捕获bash发送到您的terminal的输出。 你可以写一些东西来看/ dev或/ proc必要的,但是这很麻烦。 你也可以在你的术语和bash之间创build一个“特殊pipe道”,在中间的一个tee命令中redirect到你的输出文件。
但是这两种都是一种很好的解决办法。 我认为最好的办法就是终结者 ,这是一个更加现代化的输出loggingterminal。 只要检查你的日志文件的最后一个命令的结果。 一个类似于上面的bashvariables会使这个变得更简单。
执行完命令之后,有一种方法可以实现,并决定将结果存储在一个variables中:
$ find . -name foo.txt ./home/user/some/directory/foo.txt $ OUTPUT=`!!` $ echo $OUTPUT ./home/user/some/directory/foo.txt $ mv $OUTPUT somewhere/else/
或者,如果您事先知道要将结果存入variables,则可以使用反引号:
$ OUTPUT=`find . -name foo.txt` $ echo $OUTPUT ./home/user/some/directory/foo.txt
作为现有答案的替代方法:如果文件名可以包含如下所示的空格,请使用:
find . -name foo.txt | while IFS= read -r var; do echo "$var" done
正如我写的,只有当你不得不在文件名中预期空白的时候,区别才是相关的。
注意:唯一的内置东西不是关于输出,而是关于最后一个命令的状态。
如何将 export $last=$(!!)
到.bashrc或.profile文件?
编辑:没关系做各种愚蠢的事情。
编辑#2:
- 下载bash源代码
- 学习CPP
- 代码在新的魔术variables
- 利润?
你可以使用!!:1。 例:
~]$ ls *.~ class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~ ~]$ rm !!:1 rm class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~ ~]$ ls file_to_remove1 file_to_remove2 file_to_remove1 file_to_remove2 ~]$ rm !!:1 rm file_to_remove1 ~]$ rm !!:2 rm file_to_remove2
我有一个类似的需求,我想用最后一个命令的输出到下一个。 很像| | (pipe)。 例如
$ which gradle /usr/bin/gradle $ ls -alrt /usr/bin/gradle
到像 –
$ which gradle |: ls -altr {}
解决scheme:创build此自定义pipe道。 真的很简单,用xargs –
$ alias :='xargs -I{}'
基本上没有什么能为xargs创造一个短手,它像魅力一样工作,而且非常方便。 我只是在.bash_profile文件中添加别名。
这不是严格的bash解决scheme,但是您可以使用sed的pipe道获取前一个命令输出的最后一行。
首先让我们看看我在文件夹“A”
rasjani@helruo-dhcp022206::~$ find a a a/foo a/bar a/bat a/baz rasjani@helruo-dhcp022206::~$
然后,你用ls和cd的例子会变成sed&piping变成这样的东西:
rasjani@helruo-dhcp022206::~$ cd `find a |sed '$!d'` rasjani@helruo-dhcp022206::~/a/baz$ pwd /home/rasjani/a/baz rasjani@helruo-dhcp022206::~/a/baz$
所以,真正的魔法发生在sed上,你将任何曾经input的命令input到sed中,sed打印最后一行,你可以使用back ticks作为参数。 或者你也可以把它和xargs结合起来。 (shell中的“man xargs”是你的朋友)
shell没有perl类似的特殊符号来存储最后一个命令的回显结果。
学习用awk使用pipe道符号。
find . | awk '{ print "FILE:" $0 }'
在上面的例子中,你可以这样做:
find . -name "foo.txt" | awk '{ print "mv "$0" ~/bar/" | "sh" }'
find . -name foo.txt 1> tmpfile && mv `cat tmpfile` /path/to/some/dir/
尽pipe是肮脏的,但还是另一种方式。