我希望能够在后续命令中使用上次执行的命令的结果。例如,
$ find . -name foo.txt
./home/user/some/directory/foo.txt
现在让我们说我希望能够在编辑器中打开文件,或删除它,或者用它做其他事情,例如。
mv <some-variable-that-contains-the-result> /some/new/location
我该怎么办?也许使用一些bash变量?
更新
为了澄清,我不想手动分配东西。我所追求的是内置的bash变量,例如
ls /tmp
cd $_
$_
保存上一个命令的最后一个参数。我想要类似的东西,但是使用最后一个命令的输出。
最终更新:
塞斯的答案非常有效。记住一些事情:touch /tmp/x
答案 0 :(得分:87)
我不知道任何自动执行的变量。要做一些事情,除了复制粘贴结果,你可以重新运行你刚刚做的任何事情,例如
vim $(!!)
其中!!
是历史扩展,意思是“前一个命令”。
如果您希望单个文件名中包含空格或其他字符,可能会阻止正确的参数解析,请引用结果(vim "$(!!)"
)。只要它们不包含空格或其他shell解析标记,就可以一次打开多个文件。
答案 1 :(得分:67)
这是一个真正的hacky解决方案,但它似乎主要在某些时候工作。在测试期间,我注意到在命令行上获取 ^ C 时有时效果不好,不过我做了一点调整以表现得更好。
这个hack只是一个交互式模式hack,我相信我不会推荐给任何人。后台命令可能导致比正常情况更少定义的行为。其他答案是以编程方式获得结果的更好方法。
话虽如此,这是“解决方案”:
PROMPT_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)'
设置此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
答案 2 :(得分:20)
Bash是一种丑陋的语言。是的,您可以将输出分配给变量
MY_VAR="$(find -name foo.txt)"
echo "$MY_VAR"
但更好的希望你最难的 find
只返回一个结果而且那个结果没有任何&#34;奇怪的&#34;其中的字符,如回车符或换行符,因为它们在分配给Bash变量时将被静默修改。
但最好小心使用它时正确引用你的变量!
最好直接对文件执行操作,例如使用find
&#39; s -execdir
(参阅手册)。
find -name foo.txt -execdir vim '{}' ';'
或
find -name foo.txt -execdir rename 's/\.txt$/.xml/' '{}' ';'
答案 3 :(得分:12)
有多种方法可以做到这一点。一种方法是使用v=$(command)
,它将命令输出分配给v
。例如:
v=$(date)
echo $v
你也可以使用反引号。
v=`date`
echo $v
当使用旧式反引号替换形式时,反斜杠保留其字面含义,除非后跟“$”,“`”或“\”。第一个没有反斜杠的反引号会终止命令替换。使用“$(COMMAND)”表格时,括号内的所有字符组成命令;没有人受到特别对待。
编辑:在问题编辑之后,似乎这不是OP正在寻找的东西。据我所知,对于最后一个命令的输出,没有像$_
这样的特殊变量。
答案 4 :(得分:9)
我认为您可能会破解一个涉及将shell设置为包含以下内容的脚本的解决方案:
#!/bin/sh
bash | tee /var/log/bash.out.log
然后,如果你设置$PROMPT_COMMAND
输出分隔符,你可以编写一个帮助函数(可能称为_
),它可以获取该日志的最后一个块,因此你可以使用它: / p>
% find lots*of*files
...
% echo "$(_)"
... # same output, but doesn't run the command again
答案 5 :(得分:9)
这很容易。使用反引号:
var=`find . -name foo.txt`
然后你可以在将来的任何时候使用它
echo $var
mv $var /somewhere
答案 6 :(得分:8)
Disclamers:
在tmux中运行交互式shell时,您可以轻松访问终端上当前显示的数据。我们来看看一些有趣的命令:
是的,这给了我们很多可能性:)至于我,我设置了一个简单的别名:alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1"
现在每次我需要访问最后一行时我只使用$(L)
得到它。
这与程序使用的输出流(stdin或stderr),打印方法(ncurses等)和程序的退出代码无关 - 只需要显示数据。
答案 7 :(得分:6)
我刚从这里的建议中提取了这个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
更新:匿名用户建议将echo
替换为printf '%s\n'
,其优势在于它不会在抓取的文本中处理-e
等选项。因此,如果您期望或遇到这样的特点,请考虑这个建议。另一种选择是使用cat <<<$grab
代替。
答案 8 :(得分:6)
您可以在bash配置文件中设置以下别名:
alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))'
然后,通过在任意命令后键入“s”,可以将结果保存到shell变量“it”。
所以示例用法是:
$ which python
/usr/bin/python
$ s
$ file $it
/usr/bin/python: symbolic link to `python2.6'
答案 9 :(得分:5)
使用反引号捕获输出:
output=`program arguments`
echo $output
emacs $output
答案 10 :(得分: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
答案 11 :(得分:4)
我通常会做其他人建议的......没有作业:
$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 `!!`
答案 12 :(得分:2)
如果你想要的只是重新运行你的最后一个命令并得到输出,那么一个简单的bash变量就可以了:
LAST=`!!`
那么你可以在输出上运行命令:
yourCommand $LAST
这将生成一个新进程并重新运行您的命令,然后为您提供输出。这听起来像你真正想要的命令输出的bash历史文件。这意味着您需要捕获bash发送到终端的输出。你可以写一些东西来观察/ dev或/ proc必要的,但这很麻烦。你也可以在你的术语和bash之间创建一个“特殊管道”,中间有一个tee命令,可以重定向到你的输出文件。
但这两种都是一种黑客解决方案。我认为最好的事情是terminator,这是一个更加现代化的终端,具有输出记录功能。只需检查您的日志文件以获取最后一个命令的结果。类似于上面的bash变量会使这更简单。
答案 13 :(得分:1)
可以使用神奇的文件描述符和lastpipe
shell选项来完成。
必须使用脚本来完成-“ lastpipe”选项在交互模式下不起作用。
这是我测试过的脚本:
$ cat shorttest.sh
#!/bin/bash
shopt -s lastpipe
exit_tests() {
EXITMSG="$(cat /proc/self/fd/0)"
}
ls /bloop 2>&1 | exit_tests
echo "My output is \"$EXITMSG\""
$ bash shorttest.sh
My output is "ls: cannot access '/bloop': No such file or directory"
我在这里做的是:
设置外壳程序选项shopt -s lastpipe
。不起作用
否则,您将丢失文件描述符。
确保我的stderr也被2>&1
将输出插入函数,以便可以将stdin文件描述符 引用。
通过获取变量的内容来设置变量
/proc/self/fd/0
文件描述符,即stdin。
我正在使用它来捕获脚本中的错误,因此如果命令有问题,我可以停止处理脚本并立即退出。
shopt -s lastpipe
exit_tests() {
MYSTUFF="$(cat /proc/self/fd/0)"
BADLINE=$BASH_LINENO
}
error_msg () {
echo -e "$0: line $BADLINE\n\t $MYSTUFF"
exit 1
}
ls /bloop 2>&1 | exit_tests ; [[ "${PIPESTATUS[0]}" == "0" ]] || error_msg
通过这种方式,我可以在每个需要检查的命令后面添加2>&1 | exit_tests ; [[ "${PIPESTATUS[0]}" == "0" ]] || error_msg
。
现在您可以享受输出了!
答案 14 :(得分:1)
我有类似的需求,我想在下一个命令中使用last命令的输出。很像| (管)。 例如
$ which gradle
/usr/bin/gradle
$ ls -alrt /usr/bin/gradle
类似于 -
$ which gradle |: ls -altr {}
解决方案: 创建此自定义管道。非常简单,使用xargs -
$ alias :='xargs -I{}'
基本上没有为xargs创造一个简短的手,它就像魅力一样,非常方便。 我只是在.bash_profile文件中添加别名。
答案 15 :(得分:1)
作为现有答案的替代方法:如果您的文件名可以包含如下空格,请使用while
:
find . -name foo.txt | while IFS= read -r var; do
echo "$var"
done
正如我所写,只有在文件名中需要空白时才会产生差异。
NB:唯一内置的东西不是关于输出,而是关于最后一个命令的状态。
答案 16 :(得分:1)
执行命令后,这是执行此操作的一种方法,并决定将结果存储在变量中:
$ find . -name foo.txt
./home/user/some/directory/foo.txt
$ OUTPUT=`!!`
$ echo $OUTPUT
./home/user/some/directory/foo.txt
$ mv $OUTPUT somewhere/else/
或者,如果您提前知道您希望将结果存储在变量中,则可以使用反引号:
$ OUTPUT=`find . -name foo.txt`
$ echo $OUTPUT
./home/user/some/directory/foo.txt
答案 17 :(得分:1)
你可以使用!!: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
答案 18 :(得分:0)
我发现记得将命令的输出通过管道传送到特定文件中有点烦人,我的解决方案是.bash_profile
中的一个函数,该函数捕获文件中的输出并在需要时返回结果。
此命令的优点是您不必重新运行整个命令(使用find
或其他可能很关键的长期运行命令时)
很简单,将其粘贴到您的.bash_profile
中:
# catch stdin, pipe it to stdout and save to a file
catch () { cat - | tee /tmp/catch.out}
# print whatever output was saved to a file
res () { cat /tmp/catch.out }
$ find . -name 'filename' | catch
/path/to/filename
$ res
/path/to/filename
在这一点上,我倾向于将| catch
添加到所有命令的末尾,因为这样做没有成本,而且省去了重新运行需要很长时间才能完成的命令的麻烦。
此外,如果要在文本编辑器中打开文件输出,可以执行以下操作:
# vim or whatever your favorite text editor is
$ vim <(res)
答案 19 :(得分:0)
shell没有类似perl的特殊符号来存储最后一个命令的echo结果。
学习使用带有awk的管道符号。
find . | awk '{ print "FILE:" $0 }'
在上面的示例中,您可以执行以下操作:
find . -name "foo.txt" | awk '{ print "mv "$0" ~/bar/" | "sh" }'
答案 20 :(得分:0)
find . -name foo.txt 1> tmpfile && mv `cat tmpfile` /path/to/some/dir/
是另一种方式,虽然很脏。
答案 21 :(得分:0)
这不是严格意义上的bash解决方案,但您可以使用sed管道来获取前一个命令输出的最后一行。
首先让我们看一下文件夹“a”中的内容
rasjani@helruo-dhcp022206::~$ find a
a
a/foo
a/bar
a/bat
a/baz
rasjani@helruo-dhcp022206::~$
然后,你的ls和cd的例子将转向sed&amp;管道成这样的东西:
rasjani@helruo-dhcp022206::~$ cd `find a |sed '$!d'`
rasjani@helruo-dhcp022206::~/a/baz$ pwd
/home/rasjani/a/baz
rasjani@helruo-dhcp022206::~/a/baz$
所以,实际的魔法发生在sed中,你将什么输出的命令输入到sed和sed打印最后一行,你可以将它作为参数用后退滴答。或者你也可以将它与xargs结合起来。 (shell中的“man xargs”是你的朋友)