如何重用命令行的最后输出?


44

我想知道如何重用控制台的最后一个输出,即:

pv-3:method Xavier$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/Library/Python/2.6/site-packages
pv-3:method Xavier$ cd **LASTOUTPUT**

7
你不能 有一些背景的解释在这里。最好的选择是再次运行命令,如到目前为止发布的两个答案所示。
吉尔(Gilles)“所以,别再邪恶了”,

您不能捕获直接发送到设备的输出,例如/dev/tty,但是应该可以捕获发送到stdout或的任何东西stderr,这可能就足够了。
Mikel

@Gilles-当然,除非您使用@mattdm的答案!
西蒙(Simon)

@Gilles:但是可能有人会创建一个外壳程序,该外壳程序将捕获(并通过)命令的输出,并使捕获的输出可供用户从他的其他命令中引用。也许,甚至存在一些不那么流行的现有外壳,这些外壳或多或少地带来了复杂性……
imz – Ivan Zakharyaschev

Answers:


40

假设bash:

% python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.7/site-packages
% cd $(!!)
cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
% pwd
/usr/lib/python2.7/site-packages

1
谢谢!键入起来不太容易,但它胜过鼠标。
methodofaction

2
您也可以使用反引号(我不知道如何使该界面不成为wikify)而不是$(),但是我发现按一下backtick-shift-1-shift-1-backtick对我来说并不舒服,并且出于可读性的考虑,我正在尝试养成使用$()的习惯。
jsbillings 2011年

@jsbillings在下面看到我的答案。我输入\`在答案中显示`。和显示“ \”一样,通常键入“ \\”。
yasouser 2011年

3
+1我一直在想如何筑巢`backtick-commands`cd $(dirname $(which python))我来了!
Ed Brannin 2011年

21
仅需注意一点,请记住,这正在重新运行命令。如果您的命令有副作用,这可能对您不起作用。
Rich Homolka'3

13

尚未提及,请使用变量:

dir=$( python -c ... )
cd "$dir"

3
究竟。因为它是外壳,所以人们常常会忘记Bash提供的语言功能,例如循环和赋值。
埃文(Evan)

只能说cd $dir
临时用户名

3
@Aerovistae,如果您不知道该值来自何处,则必须使用引号:
glenn jackman 2015年

@glenn,(我知道这可能是另一个问题,但是如果答案很短:)您能否解释更多/提供一个示例,其中不使用引号会破坏事情?
alexey,2016年


8

所有其他解决方案都涉及修改工作流程或两次运行命令,如果运行时间很长或不可重复(例如,删除文件-重新运行它会产生不同的结果),则这可能不适合。

因此,如果需要,这是一个更复杂的想法:

.bashrc

exec > >(tee -a ~/$$.out)

PROMPT_COMMAND='LASTLINE=$(tail -n 1 ~/$$.out)'

trap 'rm ~/$$.out' EXIT

bash提示

$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.6/dist-packages
$ cd $LASTLINE
$ pwd
/usr/lib/python2.6/dist-packages

这有一些问题,所以这只是一个起点。例如,输出文件(~/<pid>.out)可能会变得非常大并填满磁盘。同样,如果tee死了,整个外壳可能会停止工作。

可以对其进行修改,以仅使用zsh中的preexecprecmd钩子捕获捕获的前一个命令的输出,或者在bash 中对其进行仿真,但这在这里要描述得更为复杂。


6
基本思想是好的,但是实现不是。Shell会话中的标准输出不是终端,而是管道,这将导致某些程序的行为有所不同。写到stdout和写到stderr或直接写到tty之间不会有任何同步,因此,例如,您可能会在下一个提示符后看到显示的命令输出。您也没有受到tee信号保护(尝试按Ctrl+C并运行更多命令)。使用script没有这些问题的实用程序。
吉尔(Gilles)“所以,别再邪恶了”,

很高兴知道!我仍在使用命令行基础知识,因此这可能对我来说是一个过大的矫正,而且我希望能够在任何计算机上使用它,但是如果我达到了一个不错的水平,我会记得的。
methodofaction

8

传统外壳的工作草案:

ttyid=$(readlink /proc/$$/fd/1)
\___/   \______/ \___/ |  |  |
  |         |      |   |  |  \- 0: stdin 
  |         |      |   |  |     1: stdout <- our interest
  |         |      |   |  |     2: stderr
  |         |      |   |  \- fd is, maybe, filedescriptor
  |         |      |   |
  |         |      |   \- $$ is the PID of the current process (shell,
  |         |      |      in our case)
  |         |      |
  |         |      \- you know, much runtime stuff is here
  |         |
  |         \- readlink extracts the symbolic link of /proc/$$/fd/1
  |            lrwx------ 1 stefan stefan 64 2011-03-18 09:11
  |            /proc/22159/fd/1 -> /dev/pts/4
  |
  \- /dev/tty3 for real shell, /dev/pts/3 for xterm

现在我们可以将屏幕显示为一个文件。需要须藤。

id=${ttyid//\/dev\/tty}
sudo cat /dev/vcs$id > screen.dump

Apropos screendump:这样命名的程序对我不再有用。也许仅适用于较早的内核。/ dev / pts / N也不适合我。也许您必须在/ dev中使用一些可选的MKDEV-我对某些内容有些晦涩/dev/cuaN,但我可能是错的。

我们希望通过管道传递输出,而不是使用screen.dump。但是它不起作用-有时它等待ENTER。

捕获不是带有换行符的普通文本文件,而是-例如-一个序列中包含80x50个字符。

要选择最后两行,请为命令输出选择1行,并为提示行选择一条,我将其还原,选择160个字符,再次还原并选择80。

rev vcs4.dat | sed 's/\(.\{160\}\).*/\1/g' | rev | sed 's/\(.\{80\}\).*/\1/g'

以防万一您想知道为什么要有一个rev程序。

批判:

  • 输入第一个命令,从而移动行。好吧-只是一项数字练习就可以选择倒数第三名。我主要在不同的窗口中工作。
  • 并非每个人都有80x50的屏幕。好吧,是的,我们知道。有$ COLUMNS和$ ROWS为您提供乐趣。
  • 输出并非始终位于底部。新鲜和年轻的贝壳可能在上面的行中。好吧-就这么简单:评估正在运行的Shell。使用哪个提示。进行一些及时的检测,并找到带有shell提示符的最后一行。之前(或2.之前)的行应包含目录。

第一张图是用explain.py制作的


+1,让我做alias tee2tty='tee $(readlink /proc/$$/fd/1)'
Tobias Kienzler 2011年

7

尝试这个:

$ cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
$ pwd
/Library/Python/2.6/site-packages

6

所以,嗯,这是一个答案:

如果在X下运行,请用鼠标选择要复制的输出,然后单击鼠标中键将其粘贴。

如果您在文本控制台上运行,则可以使用gpm执行类似的操作。


1
+1-好答案!即使您没有运行X,也可以通过使用GNU屏幕(gnu.org/software/screen)实现相同的目的
西蒙(Simon)

1
似乎如此明显,以至于我犹豫不决。但是其他所有人都很忙,要聪明。:)
mattdm 2011年

这是唯一允许OP 重用最后一行的答案-其他所有操作都需要再次运行该命令,这可能在完全不相关和灾难性之间的任何地方:)但是OP确实说过复用
simon

@simon:实际上,我的答案没有。格伦的也没有。
Mikel

@Mikel:是的,但是他们要求您事先做一些事情,或者第一次正确做。
mattdm 2011年

1

(不幸的是,这不是一个可行的答案,但还是有些奇怪。有兴趣的人可以尝试完成我将要告诉您的功能的实现。)

eshellEmacs内部,他们希望拥有这样的功能,但是它没有以完整的方式实现(但是在文档有所反映)。

例如:

~ $ pwd
~
~ $ /bin/echo $$
~
~ $ /bin/pwd
/home/imz
~ $ /bin/echo $$

~ $ 

您会看到,只有内建函数的输出可以捕获到$$变量中。

但是,好的,一些简化的编程(参见eshell-mark-output“ esh-mode.el”中的实现),您可以实现一个函数,该函数“标记”最后的输出并将其作为函数的结果返回;以便您可以在所要求的eshell命令中使用该功能-elisp函数可以在具有常规elisp语法的eshell命令中使用,例如在括号中,如下所示:

~ $ /bin/echo (buffer-name)
*eshell*
~ $ /bin/echo (car '(a b c))
a
~ $ 

0

如果您意识到要在点击之前重用输出Enter,可以将其保存在变量中:tmp=$(在行的开头和)结尾处添加。(这会删除命令输出末尾的任何空白行,并且实际上会删除任何最后的换行符;这很少有关系。)

tmp=$(python -c )
echo "$tmp"
cd "$tmp"

如果您的shell是ksh或zsh,则可以使用以下有用的函数使它更加自动化。(在bash中没有帮助,因为它要求在父shell中执行管道中的最后一条命令,只有在ksh(不是pdksh)和zsh中才是这种情况。)

keep () {
  local line IFS=$'\n'
  kept=
  while read -r line; do
    printf '%s\n' "$line"
    kept=$kept$line$IFS
  done
}
alias keep=k

使用这种方式:

python -c  |k
cd $kept

0
cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" | tee $(readlink /proc/$$/fd/1))

(建立在4485的答案上

输入的内容很多,因此请使用别名:

alias tee2tty='tee $(readlink /proc/$$/fd/1)'

然后只需致电 cd $(python -c ... | tee2tty)

当然,这要求您已经知道要对输出执行什么操作,但是具有只调用一次命令的优点。



0

有一个更好的解决方案:

!!在执行命令后打印,您将得到重复的输出。

例如

在此处输入图片说明

原版的:

https://askubuntu.com/questions/324423/how-to-access-the-last-return-value-in-bash


!!不重复上一条命令的结果,而是重新运行上一条命令。如果jot -r 1 0 1000返回一个介于0到1000之间的随机数,那么在运行该命令一次并获取之后539,运行!!将很可能给出其他一些数字。!!如果先前的命令需要花费大量时间来运行,或者重复执行不应该重复的操作(例如更改文件),则也可能是不可取的。
加勒布

1
不错的收获。尽管有一种更简单的方法来证明我是错误的:echo $ RANDOM; !!
特贝

亲爱的-对此一无所知!谢谢。
加勒布
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.