Linux last command result

Automatically capture output of last command into a variable using Bash?

Now let’s say I want to be able to open the file in an editor, or delete it, or do something else with it, e.g.

How can I do it? Maybe using some bash variable? Update: To clarify, I don’t want to assign things manually. What I’m after is something like built-in bash variables, e.g.

  • don’t forget to touch /tmp/x when trying the solution for the very first time
  • the result will only be stored if last command’s exit code was successful

After seeing your edit I thought to delete my answer. I wonder whether there is anything built-in that you are looking for.

I couldn’t find anything built-in. I was wondering if it would be possible to implement it.. maybe through .bahsrc? I think it’d be a pretty handy feature.

I am afraid all you can do is either redirect the output to file or pipe or capture it, otherwise it won’t be saved.

You can’t do that without the cooperation of the shell and the terminal, and they generally don’t cooperate. See also How do I reuse the last output from the command line? and Using text from previous commands’ output on Unix Stack Exchange.

One of the main reasons why the output of commands is not captured is because the output can be arbitrarily large — many megabytes at a time. Granted, not always that large, but big outputs cause problems.

22 Answers 22

I don’t know of any variable that does this automatically. To do something aside from just copy-pasting the result, you can re-run whatever you just did, eg

Where !! is history expansion meaning ‘the previous command’.

If you expect there to be a single filename with spaces or other characters in it that might prevent proper argument parsing, quote the result ( vim «$(!!)» ). Leaving it unquoted will allow multiple files to be opened at once as long as they don’t include spaces or other shell parsing tokens.

Copy-pasting is what I usually do in such a case, also because you typically need only a part of the output of the command. I’m surprised you are the first one to mention it.

This is a really hacky solution, but it seems to mostly work some of the time. During testing, I noted it sometimes didn’t work very well when getting a ^C on the command line, though I did tweak it a bit to behave a bit better.

This hack is an interactive mode hack only, and I am pretty confident that I would not recommend it to anyone. Background commands are likely to cause even less defined behavior than normal. The other answers are a better way of programmatically getting at results.

That being said, here is the «solution»:

PROMPT_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)' 

Set this bash environmental variable and issues commands as desired. $LAST will usually have the output you are looking for:

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 

@armandino: This of course causes programs expecting to interact with a terminal on standard-out to not work as expected (more/less) or store odd things in $LAST (emacs). But I think it is about as good as you are going to get. The only other option is to use (type)script to save a copy of EVERYTHING to a file and then use PROMPT_COMMAND to check for changes since the last PROMPT_COMMAND. This will include stuff you don’t want, though. I’m pretty sure you are not going to find anything closer to what you want that this, though.

Читайте также:  Python имя пользователя linux

To go a little bit further: PROMPT_COMMAND=’last=»$(cat /tmp/last)»;lasterr=»$(cat /tmp/lasterr)»; exec >/dev/tty; exec > >(tee /tmp/last); exec 2>/dev/tty; exec 2> >(tee /tmp/lasterr)’ which provides both $last and $lasterr .

@cdosborn: man by default sends the output through a pager. As my previous comment said: «programs expecting to interact with a terminal on standard-out to not work as expected (more/less)». more & less are pagers.

@Raphink I just wanted to point out a correction: your suggestion should end in 2> >(tee /tmp/lasterr 1>&2) because the standard output of tee must be redirected back to standard error.

Bash is kind of an ugly language. Yes, you can assign the output to variable

MY_VAR="$(find -name foo.txt)" echo "$MY_VAR" 

But better hope your hardest that find only returned one result and that that result didn’t have any «odd» characters in it, like carriage returns or line feeds, as they will be silently modified when assigned to a Bash variable.

But better be careful to quote your variable correctly when using it!

It’s better to act on the file directly, e.g. with find ‘s -execdir (consult the manual).

find -name foo.txt -execdir vim '<>' ';' 
find -name foo.txt -execdir rename 's/\.txt$/.xml/' '<>' ';' 

They are not silently modified when you assign, they are modified when you echo! You only have to do echo «$» to see this is the case.

There are more than one ways to do this. One way is to use v=$(command) which will assign the output of command to v . For example:

And you can use backquotes too.

When the old-style backquoted form of substitution is used, backslash retains its literal meaning except when followed by «$», «`», or «\». The first backticks not preceded by a backslash terminates the command substitution. When using the «$(COMMAND)» form, all characters between the parentheses make up the command; none are treated specially.

EDIT: After the edit in the question, it seems that this is not the thing that the OP is looking for. As far as I know, there is no special variable like $_ for the output of last command.

It’s quite easy. Use back-quotes:

And then you can use that any time in the future

echo $var mv $var /somewhere 
  • This answer is late half a year 😀
  • I’m a heavy tmux user
  • You have to run your shell in tmux for this to work

When running an interactive shell in tmux, you can easily access the data currently displayed on a terminal. Let’s take a look at some interesting commands:

  • tmux capture-pane: this one copies the displayed data to one of the tmux’s internal buffers. It can copy the history that’s currently not visible, but we’re not interested in that now
  • tmux list-buffers: this displays the info about the captured buffers. The newest one will have the number 0.
  • tmux show-buffer -b (buffer num): this prints the contents of the given buffer on a terminal
  • tmux paste-buffer -b (buffer num): this pastes the contents of the given buffer as input
Читайте также:  Самый маленький линукс дистрибутив

Yeah, this gives us a lot of possibilities now 🙂 As for me, I set up a simple alias: alias L=»tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1″ and now every time I need to access the last line i simply use $(L) to get it.

This is independent of the output stream the program uses (be it stdin or stderr), the printing method (ncurses, etc.) and the program’s exit code — the data just needs to be displayed.

Hey, thanks for this tmux tip. I was looking for basically the same thing as the OP, found your comment, and coded up a shell script to let you pick and paste part of the output of a previous command using the tmux commands you mention and Vim motions: github.com/bgribble/lw

A great answer that I came across some 9 years later. In the meantime, a few things changed in tmux. First, tmux assigns a default buffer-prefix name of «buffer», so the tmux showb -b 0 above would be tmux showb -b buffer0 . But that still doesn’t work because the most recent buffer is now the highest numbered buffer, rather than 0. So you’ll need use capture-pane -p buffname . But the biggest problem that I haven’t solved is that tmux seems to return blank lines up to the end of the screen, so this solution only works if the cursor is at the bottom of the screen in the first place.

I think you might be able to hack out a solution that involves setting your shell to a script containing:

#!/bin/sh bash | tee /var/log/bash.out.log 

Then if you set $PROMPT_COMMAND to output a delimiter, you can write a helper function (maybe called _ ) that gets you the last chunk of that log, so you can use it like:

% find lots*of*files . % echo "$(_)" . # same output, but doesn't run the command again 

You could set up the following alias in your bash profile:

alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))' 

Then, by typing ‘s’ after an arbitrary command you can save the result to a shell variable ‘it’.

So example usage would be:

$ which python /usr/bin/python $ s $ file $it /usr/bin/python: symbolic link to `python2.6' 

Thank you! This is what I needed to implement my grab function that copies nth line from last command to clipboard gist.github.com/davidhq/f37ac87bc77f27c5027e

Capture the output with backticks:

output=`program arguments` echo $output emacs $output 

I just distilled this bash function from the suggestions here:

> grab date Do 16. Feb 13:05:04 CET 2012 > echo $grab Do 16. Feb 13:05:04 CET 2012 

Update: an anonymous user suggested to replace echo by printf ‘%s\n’ which has the advantage that it doesn’t process options like -e in the grabbed text. So, if you expect or experience such peculiarities, consider this suggestion. Another option is to use cat

Quoting from man bash : «Here Strings: A variant of here documents, the format is:

By saying «I’d like to be able to use the result of the last executed command in a subsequent command», I assume — you mean the result of any command, not just find.

Читайте также:  Linux find files more than

If thats the case — xargs is what you are looking for.

find . -name foo.txt -print0 | xargs -0 -I<> mv <> /some/new/location/<>

OR if you are interested to see the output first:

!! | xargs -0 -I<> mv <> /some/new/location/<>

This command deals with multiple files and works like a charm even if the path and/or filename contains space(s).

Notice the mv <> /some/new/location/<> part of the command. This command is build and executed for each line printed by earlier command. Here the line printed by earlier command is replaced in place of <>.

Excerpt from man page of xargs:

xargs — build and execute command lines from standard input

For more detail see man page: man xargs

I usually do what the others here have suggested . without the assignment:

$find . -iname '*.cpp' -print ./foo.cpp ./bar.cpp $vi `!!` 2 files to edit 

You can get fancier if you like:

$grep -R "some variable" * | grep -v tags ./foo/bar/xxx ./bar/foo/yyy $vi `!!` 

If all you want is to rerun your last command and get the output, a simple bash variable would work:

So then you can run your command on the output with:

This will spawn a new process and rerun your command, then give you the output. It sounds like what you would really like would be a bash history file for command output. This means you will need to capture the output that bash sends to your terminal. You could write something to watch the /dev or /proc necessary, but that’s messy. You could also just create a «special pipe» between your term and bash with a tee command in the middle which redirects to your output file.

But both of those are kind of hacky solutions. I think the best thing would be terminator which is a more modern terminal with output logging. Just check your log file for the results of the last command. A bash variable similar to the above would make this even simpler.

Источник

Return last command executed in shell-script

In a bash-script I’d like to retrieve the last command which was executed. In bash itself the following command works like a charm.

lastCommand=$(echo `history |tail -n2 |head -n1` | sed 's/6* //') 

Inside scripts however history doesn’t work at all. Is there a way to retrieve the command inside a script?

2 Answers 2

For bash v4+ :

Use interactive mode in shell.

and history inside of your script will work.

 $ cat test.sh #!/bin/bash history | wc -l $ ./test.sh 0 $ sed -i '1s/bash/bash -i/' test.sh $ ./test.sh 6495 

Commands was executed inside of script are not recorded into history.

For bash v3 (and possible for older ones)

  • The way above doesn’t work for this vesions of bash. However you can remove she-bang at all and history will work well. This way also works great for bash v4.
  • set she-bang as interactive and do not forget about set -o history like chepner mentioned.

PS. history |tail -n2 |head -n1 doesn’t equal to the last command. it is command before last one.

Note if last or prelast commands were multiline it won’t return the correct result.

btw in console you can use !-2 to refer to prelast command instead of your strange construction. unfortunately it seems doesn’t work in shell script even in interactive mode.

Источник

Оцените статью
Adblock
detector