48

I'd like to know how to reuse the last output from the console, ie:

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**
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232

11 Answers11

43

Assuming history expansion is enabled, that you're running Bash or some other shell that supports it, that the command is idempotent, and that waiting for it to run a second time is not an issue, you could use the !! form of history expansion to get the last command line again, to run the previous command again in a command substitution:

% 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
ilkkachu
  • 138,973
jsbillings
  • 24,406
  • 1
    Thanks! Not too easy to type but it beats going for the mouse. – methodofaction Mar 11 '11 at 01:38
  • 2
    You could also use backticks (which I can't figure out how to make this interface not wikify) instead of $(), but I've found that it's uncomfortable for me to hit backtick-shift-1-shift-1-backtick, and I'm trying to get into the habit of using $() when possible for readability's sake. – jsbillings Mar 11 '11 at 13:40
  • @jsbillings see my answer below. I typed \` to display ` in the answer. And to display '', as usual type '\'. – yasouser Mar 11 '11 at 16:27
  • 3
    +1 I've been wondering how to nest \backtick-commands``! cd $(dirname $(which python))here I come! – Ed Brannin Mar 11 '11 at 17:52
  • 22
    Just a note, remember that this is rerunning the command. If your command has side effects, this may not work for you. – Rich Homolka Mar 16 '11 at 23:08
  • I use \!!`` all the time. – johnsyweb Mar 18 '11 at 09:59
  • Would it be possible to create an alias for this in some way, so that you could call it for example "lr" (for "last result")? I tried naively with "alias ls=$(!!)" but that didn't work (for probably obvious reasons) – Viktor Nordling Jul 01 '13 at 05:23
  • I should add that it works fine in zsh too. – Pablo Olmos de Aguilera C. Aug 22 '13 at 00:26
  • This answers the OP's question, but if I were you I'd mention that !! reruns the last command. The difference might be important if the command has side effects (as mentioned by Rich Homolka), takes a long time to execute or if some other process changes the command's input between two executions. In it's current state the answer combined with the question might confuse new uses. – Андрей Беньковский Oct 23 '16 at 15:58
12

Not yet mentioned, use a variable:

dir=$( python -c ... )
cd "$dir"
glenn jackman
  • 85,964
11

All the other solutions involve modifying your workflow or running the command twice, which might not be suitable if it takes a long time to run, or is not repeatable (e.g. it deletes a file - rerunning it would produce a different result).

So here's a more complicated idea if you need it:

.bashrc

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

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

trap 'rm ~/$$.out' EXIT

bash prompt

$ 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

This has some issues, so it's just meant as a starting point. For example, the output file (~/<pid>.out) might grow very large and fill up your disk. Also, your whole shell could stop working if tee dies.

It could be modified to only capture the output from the previous command using preexec and precmd hooks in zsh, or an emulation of them in bash, but that's more complicated to describe here.

Mikel
  • 57,299
  • 15
  • 134
  • 153
  • 6
    The basic idea is good, but the implementation is not. The standard output in the shell session is not a terminal but a pipe, which will cause some programs to behave differently. There will not be any synchronization between writes to stdout and writes to stderr or direct to the tty, so for example you might see command output displayed after the next prompt. You also haven't protected tee from signals (try pressing Ctrl+C and running a more few commands). Use the script utility which has none of these problems. – Gilles 'SO- stop being evil' Mar 10 '11 at 21:12
  • Good to know! I'm still working on my command line basics so this is possibly an overkill for me, plus I want to be able to use it on any computer, but I'll remember it if I ever reach a good level. – methodofaction Mar 11 '11 at 01:42
9

A working draft for a traditional shell:

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

Now we can cat the screen to a file. Needs sudo.

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

Apropos screendump: so named program doesn't work for me any more. Maybe for older kernels only. /dev/pts/N didn't work for me too. Maybe you have to some optional MKDEV in /dev - I remember darkly about some /dev/cuaN, but I may be wrong.

We would like to pipe the output instead of using screen.dump. But somehow it doesn't work - sometimes it waits for ENTER.

The capturing isn't a normal textfile with linefeeds, but with - for example - 80x50 chars in one sequence.

To pick the last 2 lines, 1 for the output of the command, and one for the prompting line, I revert it, pick 160 chars, revert again and pick 80.

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

Just in case you ever wondered, why there is a rev program.

Critique:

  • The first commands are entered, thus moving the line ahed. Well - just a numerical excercise to pick the 3rd-last line or something. I worked mainly in a different window.
  • Not everybody has a 80x50 screen. Well, yes, we know. There is $COLUMNS and $ROWS for your pleasure.
  • The output is not allways at the bottom. A fresh and young shell might be in the upper rows. Well - simple as that: Evaluate what shell is running. Which prompt is used. Do some prompt detection and find the last line with a shell-prompt. The line before (or 2. before) should contain the directory.

The first diagram is made with explain.py

user unknown
  • 10,482
7

Try this:

$ cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
$ pwd
/Library/Python/2.6/site-packages
bahamat
  • 39,666
  • 4
  • 75
  • 104
6

So, uh, here's an answer:

If you're running under X, select the output you want with the mouse to copy it, and then middle-click to paste it.

If you're running on a text console, you can do a similar thing with gpm.

mattdm
  • 40,245
  • 1
    +1 -- good answer! you could achieve the same thing, even if you're not running X, by using GNU screen (http://www.gnu.org/software/screen/). – simon Mar 11 '11 at 01:15
  • 1
    It seemed so obvious that I was hesitant to say it. But everyone else is so busy being clever. :) – mattdm Mar 11 '11 at 15:25
  • it's the only answer here which allows the OP to reuse the last line -- everything else entails running the command again, which could be anywhere between utterly irrelevant and catastrophic :) But the OP did say reuse. – simon Mar 11 '11 at 15:47
  • @simon: Actually, my answer doesn't. Neither does glenn's. – Mikel Mar 18 '11 at 01:08
  • @Mikel: True, but they require you doing something beforehand, or correctly the first time. – mattdm Mar 22 '11 at 11:27
1

(It's not a working answer, unfortunately, but still something curious. Someone interested could well try to complete the implementation of the feature I'm going to tell you about.)

In eshell inside Emacs, they wanted to have such a feature but it's not implemented in a complete way (which is however reflected in the documentation).

For example:

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

~ $ 

You see, only the output of builtins can be captured into the $$ variable.

But well, some elisp programming (cf. eshell-mark-output implementation in "esh-mode.el"), and you could implement a function that "marks" the last output and returns it as the function's result; so that you can use that function in a eshell command you are asking for -- elisp functions can be used in eshell commands with the usual elisp syntax, i.e. in parentheses, like this:

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

There is a better solution:

Just print !! after executed command and you will get repeated output.

E.g.

enter image description here

Original:

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

Tebe
  • 185
  • !! doesn't repeat the outcome from the last command, it re-runs the last command. If jot -r 1 0 1000 returns a single random number between 0 and 1000, then after running that command once and getting 539, running !! will most likely give some other number. !! may also be undesirable if the previous command takes significant time to run, or repeats an operation that shouldn't be repeated (like changing a file). – Caleb Jan 24 '18 at 15:52
  • 1
    nice catch. Though there is an easier way to prove me wrong: echo $RANDOM; !! – Tebe Jan 24 '18 at 20:33
  • Sweet -- didn't know about that! Thanks. – Caleb Jan 25 '18 at 02:10
0
$ cd \`python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"\`

will do the trick.

Read here for more details: Command substitution.

jofel
  • 26,758
yasouser
  • 416
0

If you realize you're going to want to reuse the output before you hit Enter, you can save it in a variable: add tmp=$( at the beginning of the line and ) at the end. (This removes any blank line at the end of the command output, and in fact removes any final newline; this rarely matters.)

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

If your shell is ksh or zsh, here's a useful function you can use to make this more automatic. (It's no help in bash because it requires the last command in a pipeline to be executed in the parent shell, which is only the case in ksh (not pdksh) and zsh.)

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

Use it this way:

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))

(building up on 4485's answer)

That's lots of typing, so make an alias:

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

Then simply call cd $(python -c ... | tee2tty)

This of course requires you to already know what you want to do with the output but has the advantage of calling the command only once.