MUTE='&> /dev/null'
echo "text" $MUTE
Is there a way to make that work keeping the redirection inside the variable?
IMHO it would be more elegant to use the presence / value of the variable to conditionally close the file descriptors e.g.
$ cat myscript.sh
#!/bin/bash
if [ -n "$MUTE" ]; then
exec &>-
fi
echo somestuff
echo someerr >&2
then
$ ./myscript.sh
somestuff
someerr
but
$ MUTE=yes ./myscript.sh
$
If you really want to toggle the redirection, you could consider creating a shell function that duplicates the file descriptor(s) before closing them, and then restores the duplicates to re-enable the original streams e.g.
#!/bin/bash
function mute {
case "$1" in
"on")
exec 3>&1-
exec 4>&2-
;;
"off")
exec 1>&3-
exec 2>&4-
;;
*)
esac
}
# Demonstration:
echo "with mute on: "
mute on
ls somefile
ls nofile
mute off
echo "with mute off: "
ls somefile
ls nofile
Result:
$ ./mute.sh
with mute on:
with mute off:
somefile
ls: cannot access nofile: No such file or directory
From Bash Reference Manual: Simple Command Expansion:
- The words that the parser has marked as variable assignments (those preceding the command name) and redirections are saved for later processing.
- The words that are not variable assignments or redirections are expanded (see Shell Expansions). If any words remain after expansion, the first word is taken to be the name of the command and the remaining words are the arguments.
- Redirections are performed as described above (see Redirections).
This means that the command parser first identifies all the redirections, then performs the various expansions and finally resolves the redirections it previously identified: those don't include possible redirections resulting from the expansions.
However from help eval
:
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
So using eval
you could create a sort of level of indirection which will allow the command to be processed twice:
MUTE='&> /dev/null'
eval echo "text" $MUTE
$ MUTE='&> file'
$ eval echo "text" $MUTE
$ cat file
text
One could use a function that writes its stdin
to wherever you want it.
$> MUTE(){ cat /dev/stdin > testFile.txt ; }
$> df | MUTE
$> cat testFile.txt
Filesystem 1K-blocks Used Available Use% Mounted on
udev 1954208 4 1954204 1% /dev
tmpfs 393160 3548 389612 1% /run
/dev/sda1 115247656 95511252 13859056 88% /
none 4 0 4 0% /sys/fs/cgroup
none 5120 0 5120 0% /run/lock
none 1965792 872 1964920 1% /run/shm
none 102400 128 102272 1% /run/user
cgmfs 100 0 100 0% /run/cgmanager/fs
Or we could tell the function to execute whatever we want with redirection
$> MUTE(){ "$@" > testFile.txt ; }
$> MUTE lsblk
$> cat testFile.txt
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 111.8G 0 disk
└─sda1 8:1 0 111.8G 0 part /
Non-standard way, hackery , but it kind of works :)
It works this way, I don't know if it is usable for your approach:
MUTE='&> /dev/null'
bash -c "echo \"text\" $MUTE"