Reusing output from last command in Bash

2019-01-16 05:10发布

问题:

Is the output of a Bash command stored in any register? E.g. something similar to $? capturing the output instead of the exit status.

I could assign the output to a variable with:

output=$(command)

but that's more typing...

回答1:

You can use this: $(!!) to recompute (not re-use) the output of the last command.

The !! on its own executes the last command.

$ > echo pierre
pierre
$ > echo my name is $(!!)
echo my name is $(echo pierre)
my name is pierre


回答2:

The answer is no. Bash doesn't allocate any output to any parameter or any block on its memory. Also, you are only allowed to access Bash by its allowed interface operations. Bash's private data is not accessible unless you hack it.



回答3:

One way of doing that is by using trap DEBUG:

f() { bash -c "$BASH_COMMAND" >& /tmp/out.log; }
trap 'f' DEBUG

Now most recently executed command's stdout and stderr will be available in /tmp/out.log

Only downside is that it will execute a command twice: once to redirect output and error to /tmp/out.log and once normally. Probably there is some way to prevent this behavior as well.



回答4:

If you are on mac, and don't mind storing your output in the clipboard instead of writing to a variable, you can use pbcopy and pbpaste as a workaround.

For example, instead of doing this to find a file and diff its contents with another file:

$ find app -name 'one.php' 
/var/bar/app/one.php

$ diff /var/bar/app/one.php /var/bar/two.php

You could do this:

$ find app -name 'one.php' | pbcopy
$ diff $(pbpaste) /var/bar/two.php

The string /var/bar/app/one.php is in the clipboard when you run the first command.

By the way, pb in pbcopy and pbpaste stand for pasteboard, a synonym for clipboard.



回答5:

Inspired by anubhava's answer, which I think is not actually acceptable as it runs each command twice.

save_output() { 
   exec 1>&3 
   { [ -f /tmp/current ] && mv /tmp/current /tmp/last; }
   exec > >(tee /tmp/current)
}

exec 3>&1
trap save_output DEBUG

This way the output of last command is in /tmp/last and the command is not called twice.



回答6:

Like konsolebox said, you'd have to hack into bash itself. Here is a quite good example on how one might achieve this. The stderred repository (actually meant for coloring stdout) gives instructions on how to build it.

I gave it a try: Defining some new file descriptor inside .bashrc like

exec 41>/tmp/my_console_log

(number is arbitrary) and modify stderred.c accordingly so that content also gets written to fd 41. It kind of worked, but contains loads of NUL bytes, weird formattings and is basically binary data, not readable. Maybe someone with good understandings of C could try that out.

If so, everything needed to get the last printed line is tail -n 1 [logfile].



回答7:

Not sure exactly what you're needing this for, so this answer may not be relevant. You can always save the output of a command: netstat >> output.txt, but I don't think that's what you're looking for.

There are of course programming options though; you could simply get a program to read the text file above after that command is run and associate it with a variable, and in Ruby, my language of choice, you can create a variable out of command output using 'backticks':

output = `ls`                       #(this is a comment) create variable out of command

if output.include? "Downloads"      #if statement to see if command includes 'Downloads' folder
print "there appears to be a folder named downloads in this directory."
else
print "there is no directory called downloads in this file."
end

Stick this in a .rb file and run it: ruby file.rb and it will create a variable out of the command and allow you to manipulate it.



回答8:

I have an idea that I don't have time to try to implement immediately.

But what if you do something like the following:

$ MY_HISTORY_FILE = `get_temp_filename`
$ MY_HISTORY_FILE=$MY_HISTORY_FILE bash -i 2>&1 | tee $MY_HISTORY_FILE
$ some_command
$ cat $MY_HISTORY_FILE
$ # ^You'll want to filter that down in practice!

There might be issues with IO buffering. Also the file might get too huge. One would have to come up with a solution to these problems.