Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This is a noob question, but 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**
share|improve this question
7  
You can't; there is some background explanation here. Your best bet is to run the command again, as seen in the two answers posted so far. –  Gilles Mar 10 '11 at 20:19
    
You can't capture output sent directly to a device such as /dev/tty, but it should be possible to capture anything sent to stdout or stderr, which might be adequate. –  Mikel Mar 10 '11 at 20:26
    
@Gilles -- unless you use @mattdm's answer, of course! –  simon Mar 11 '11 at 1:16
    
@Gilles: but there might be a shell created by someone that will capture (and pass through) the outputs of the commands and make the captured outputs available for the user to refer to from his further commands. Perhaps, there are even some existing, not so popular shells that allow this with more or less complications... –  imz -- Ivan Zakharyaschev Mar 16 '11 at 1:09
    
@imz: Not a shell, but there's the script utility that logs all terminal output. And there's also Emacs; see the related question Would it be possible to jump between prev/next command prompts?. –  Gilles Mar 16 '11 at 19:42

10 Answers 10

up vote 32 down vote accepted

Assuming 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
share|improve this answer
    
Thanks! Not too easy to type but it beats going for the mouse. –  Duopixel Mar 11 '11 at 1: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
9  
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

Not yet mentioned, use a variable:

dir=$( python -c ... )
cd "$dir"
share|improve this answer
1  
Exactly. Because it's a shell, people often forget about the language features Bash provides, such as loops and assignment. –  Evan Mar 11 '11 at 1:09

Try this:

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

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.

share|improve this answer
1  
+1 -- good answer! you could achieve the same thing, even if you're not running X, by using GNU screen (gnu.org/software/screen). –  simon Mar 11 '11 at 1: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 1:08
    
@Mikel: True, but they require you doing something beforehand, or correctly the first time. –  mattdm Mar 22 '11 at 11:27

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.

share|improve this answer
4  
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 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. –  Duopixel Mar 11 '11 at 1:42

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

share|improve this answer
    
+1, made me do alias tee2tty='tee $(readlink /proc/$$/fd/1)' –  Tobias Kienzler Mar 18 '11 at 9:17

(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
~ $ 
share|improve this answer

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
share|improve this answer
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.

share|improve this answer
$ 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.

share|improve this answer
1  
arumug: bahamat has already posted almost the same answer. Your version with backticks won't always work if there are already backticks in the command. –  Gilles Mar 12 '11 at 0:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.