Error messages are usually written to stderr
, and you're only piping stdout
to grep
. To pipe both stdout and stderr, in Bourne-like shells of fish
, you do:
whatis... 2>&1 | grep -v 'nothing appropriate'
Note that it means stdout and stderr end up being merged on stdout.
The shell in there sees a pipeline, so it splits it into whatis... 2>&1
and grep -v 'nothing appropriate'
and plumbs them with the stdout (file descriptor 1) of the left one being the writing end of a pipe and the stdin (fd 0) of the right one being the other end of that pipe, each side running concurrently in separate processes.
On each side, the redirections are processed. 2>&1
says: redirect fd 2 to the same thing as opened on fd 1, here the pipe. So both fd 1 and 2 go to the pipe.
The equivalent syntax for rc-like shells is whatis... >[2=1] | grep...
and with csh
-like shells: whatis... |& grep...
(also works in zsh).
With ksh93
, zsh
or bash
, you can also send stderr
only to a filtering pipe with:
whatis... 2> >(grep -v 'nothing appropriate' >&2)
But note that that grep
command is not waited for so you may end-up seeing the other error messages after the command has returned. That can be avoided in zsh
with:
{whatis...} 2> >(grep -v 'nothing appropriate' >&2)
(or more painfully in ksh93
and bash
).
In yash
, you can use process redirection (with similar syntax as process substitution, but different in that it's a redirection operator, not an expansion), with the same problem wrt the filtering command not being waited for:
whatis... 2>(grep -v 'nothing appropriate' >&2)
Beware that with cut -d "." -f 1
you end up changing org.gnome.Settings.desktop
to org
instead of org.gnome.Settings
. Because you're invoking split+glob, you'll also have problems for application names that contain characters of $IFS
or glob characters.
With zsh
, you'd do:
whatis -- /usr/share/applications/*.desktop(:t:r) |& grep -v 'nothing appropriate'
Where :t
takes the t
ail (dirname) of the file and :r
the root name (without extension) and |&
is short for 2>&1 |
.
In bash
, you can do something approaching with:
(
shopt -s failglob
set /usr/share/applications/*.desktop
set -- "${@##*/}"
whatis -- "${@%.*}" 2>&1
) | grep -v 'nothing appropriate'
Where "${@##*/}"
does the equivalent of :t
, "${@%.*}"
the equivalent of :r
.
With GNU ls
9.0 or newer, you can also do:
ls --zero /usr/share/applications/ |
LC_ALL=C sed -zn 's/\.desktop$//p' |
xargs -r0 whatis -- 2>&1 |
grep -v 'nothing appropriate'
Where ls --zero
outputs the list in a post-processable format, sed
removes the .desktop
extension and outputs the result if there was a substitution (therefore excluding files without .desktop
extension), xargs
passes the list the whatis
, and grep
filters out the nothing appropriate
errors.
With GNU basename
, you can also do:
(
shopt -s failglob
basename -zs .desktop /usr/share/applications/*.desktop
) |
xargs -r0 whatis -- 2>&1 |
grep -v 'nothing appropriate'
Also beware that the name of the desktop files often don't match the name of the executable they execute if any and so are likely to not have a corresponding man page.
Instead of passing the rootname to whatis
, you could also extract some fields of those .desktop
files. For instance:
(cd /usr/share/applications &&
grep -HPom1 -e '^GenericName=\K.*' -- *.desktop
)
Would extract the value of the first occurrence of a GenericName
field in those files.
whatis $(ls /usr/share/applications | cut -d "." -f 1) 2>&1 | grep -i -v "nothing appropriate" – Lee Oct 01 '22 at 16:32
io.snapcraft.SessionAgent.desktop
file for instance, you end up doingwhatis io
and could getIO (3perl) - load various IO modules
for that which is unrelated. See the rest of my answer for more reliable ways to remove the.desktop
extension. – Stéphane Chazelas Oct 01 '22 at 16:39