Can zsh access the stdout of last run program

outputterminalzsh

I often use find or locate to find out about paths.

(~) locate foobar.mmpz
/home/progo/lmms/projects/foobar.mmpz

The next step is often to open or otherwise manipulate the files. In a happy case like above, I can do this:

(~) ls `!!`
ls `locate foobar.mmpz`
/home/progo/lmms/projects/foobar.mmpz

But nobody's too happy when there are many lines of output, some of which may not be paths or something else of that kind. Besides, rerunning potentially wasteful commands is not that elegant either.

Would there be a way to hook up zsh to store the stdout into an array for later manipulation? After all, it's the shell's job to redirect the streams to the user. I'm thinking it could store the first N and last N lines in a variable for immediate later use, like $? and others.

Ok so this is pretty cool: https://unix.stackexchange.com/a/59704/5674. I'm now asking about the zsh know-how (and porting the code to zsh) to rig this kind of capture after each run line.

Best Answer

There is no feature to capture the output from the screen on most terminal emulators. I seem to recall the author of xterm (the “reference” terminal emulator) stating that it would be difficult to implement. Even if that was possible, the shell would have to keep track of where the last prompt had been.

So you won't escape having to run the command again, unless you use a terminal-specific, manual mechanism such as copy-pasting with the mouse in xterm or with the keyboard in Screen.

It would be highly impractical for the shell to automatically capture the output of commands, because it cannot distinguish between commands that have complex terminal and user interactions from commands that simply output printable characters.

You can rerun the command and capture its output. There are various ways to do each. To rerun the command, you can use:

  • !! history substitution — most convenient to type;
  • fc -e -, which can be used in a function.

To capture the output, you can use command substitution, or a function like the following:

K () {
  lines=("${(f@)$(cat)}")
}
!! |K

This sets the lines array to the output of the command that's piped into it.

Related Question