How to make a pipeline wait for end-of-file or stop after an error?
How can I make the pdf reader (and any other command in a pipe chain) to only run when its input reach a end-of-file or when it receives an input at all?
There is ifne
(in Debian it's in moreutils
package):
ifne
runs the following command if and only if the standard input is not empty.
In your case:
… | ifne zathura -
All commands in a pipeline starts pretty much at the same time. It's only the I/O over the pipe that synchronises them. Also, a pipe can only hold as much information as the pipe's buffer allows.
You can therefore not avoid running one stage of a pipeline, because
- the command in that stage is started as soon as all other stages are started anyway, and
- if the command did not consume the input that comes in over the pipe, it would block the previous stages of the pipeline.
Instead, write the output to a file while letting the pipeline finish. Then use that file.
Example (as a function taking one argument):
myman () {
tmpfile=$( mktemp )
if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile" && [ -s "$tmpfile" ]
then
zathura "$tmpfile"
fi
rm -f "$tmpfile"
}
This additionally would not run the zathura
program if the pipeline failed (the xargs
part returned non-zero) or the generated file is empty.
In the bash
shell, you could also want to set the pipefail
shell option with set -o pipefail
to have the pipeline return the exit status of the first command in the pipeline that fails. And you would want to make the tmpfile
variable local
:
myman () {
local tmpfile=$( mktemp )
if [ -o pipefail ]; then
set -o pipefail
trap 'set +o pipefail' RETURN
fi
if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile"
then
zathura "$tmpfile"
fi
rm -f "$tmpfile"
}
This sets the pipefail
option for the duration of the function, if it wasn't already set, and then unsets it if needed. It gets rid of the -s
test on the output file.
Pdf files are supposed to be seekable; any pdf viewer will have to look first at the trailer and from there jump to the offsets from the xref table.
Since pipes are not seekable, zathura
is using an obfuscating trick, where it's copying all the input to a temporary file, and then use that temporary file as usually. This kind of "clever" trick is creating false hopes and is leading people to assume that pdf files are streamable.
But anyways, zathura
really does wait for the EOF before displaying the document, you don't have to do anything for that to hapen:
(sleep 10; cat file.pdf) | zathura -
# will really show the content of file.pdf after 10 seconds
The problem is that zathura
has no option to only open the window if the file's OK, and exit with an error if that's not the case -- it will just stay there as if everything's OK:
$ dd if=file.pdf bs=50000 count=1 status=none | zathura -
error: could not open document # its window still hanging around showing nothing
$ echo $?
0 # really?
So even if you're redirecting the output to a temporary file yourself, and are only running zathura
if everything was OK, there's no guarantee that the user will not be served with a black window if zathura
doesn't like the output for one reason or another.
Btw,
man -X man
will display a manpage in an X11 window with gxditview
, even if it looks straight out of the '70 ;-)
And, of course, you could always use:
... | xargs xterm -e man
which, besides many other enhancements, will let you use regular expressions in searches and proper text selection.