Bash function that accepts input from parameter or pipe
See Stéphane Chazelas's answer for a better solution.
You can use /dev/stdin
to read from standard input
b64decode()
{
if (( $# == 0 )) ; then
base64 --decode < /dev/stdin
echo
else
base64 --decode <<< "$1"
echo
fi
}
$# == 0
checks if number of command line arguments is zerobase64 --decode <<< "$1"
one can also useherestring
instead of usingecho
and piping tobase64
Here it should just be:
b64decode() {
if [ "$#" -gt 0 ]; then
# concatenated arguments fed via a pipe.
printf %s "$@" | base64 --decode
else
base64 --decode # read from stdin
fi
ret=$?
echo # add one newline character
return "$ret" # return with base64's exit status to report decoding
# errors if any.
}
In any case, do not use base64 --decode < /dev/stdin
. At best (on most systems) < /dev/stdin
does nothing, it just does the equivalent of dup2(0,0)
(duplicating fd 0 onto fd 0, a no-op).
But on Linux or Cygwin, < /dev/stdin
does not work properly here. On those systems, opening /dev/stdin
is not like duplicating stdin, it reopens from scratch and independently the same file as is currently opened on stdin.
So if previously stdin was pointing in the middle of some regular file, after < /dev/stdin
, you'll end up with stdin now pointing at the start of that file. If stdin was the writing end of a pipe (which it shouldn't under normal circumstances), you'll end up with it being the reading end. If it was a socket, then it will fail as sockets cannot be opened. Same if you don't have permission to open that file for reading (for instance because the permissions changed or the file was originally opened on stdin using different credentials).
And after base64 --decode < /dev/stdin
returns, the current position of stdin within the file (for seekable file input) will have been left untouched, not left at the end (or wherever base64
stopped reading) since base64
's stdin was on a different open file description.
Sundeep's answer works for base64
because that utility does not support multiple lines. A more general fix for the more general case
- target utility allowing multiple commandline arguments
- pipe or redirect containing multiple lines
is something like
my_function() {
if (( ${#} == 0 )) ; then
while read -r line ; do
target_utility "${line}"
done
else
target_utility "${@}"
fi
}