I'm writing a bash script that amongst other things, starts a user specified command, sending the output to either file, file and stdout, or just stdout as required.
I don't like the duplication of the line that runs the user command which has different endings depending on the output type wanted.
#!/bin/bash
# messy but works
function my_function() {
local pid_file=$1; shift
local logfile=$1; shift
local tee_output=$1; shift
local cmd=$*; shift
# do some stuff
{ # codeblock to allow redirection of all content by default to somewhere different
# do some stuff
# This IF Block runs the user specified cmd. Output will go to different locations as specified
if [ "$logfile" = "NO_LOG" ] ; then
# ALL Output -> default stdout and default stderr
sh -c "echo \$\$ > '$pid_file'; $cmd" 1>&3 2>&4 &
else
if [ "$tee_output" -eq 1 ] ; then
# ALL Output -> logfile AND default stdout and default stderr
sh -c "echo \$\$ > '$pid_file'; $cmd" 1>&3 2>&4 | tee "$logfile" &
else
# ALL Output -> logfile
sh -c "echo \$\$ > '$pid_file'; $cmd" >> "$logfile" &
fi
fi
# do some stuff
} >> "script_output.log" 2>&1 ; # This will redirect stderr and stdout for this codeblock to file
# do some stuff
}
exec 3>&1 4>&2 ; # make a copy of the default stdout and stderr destinations
my_function cmd.pid output.log echo hi
Is there a way of rewriting this horrible IF block so that the various options are appended to the end of the sh -c "echo \$\$ > '$pid_file'; $cmd"
part that remains constant?
I think something like the following statement might be the answer, but I can't quite get it working. Can you show me a neat way of doing this please? Thanks.
# possible idea for a neater solution (not working)
sh -c "echo \$\$ > '$pid_file'; $cmd" $(if [ "$logfile" = "NO_LOG" ] ; then
echo '1>&3 2>&4 &' ;# send output to console
else
if [ "$tee_output" -eq 1 ] ; then
echo '1>&3 2>&4 | tee $logfile &' ; # send output to console AND logfile
else
echo '>> "$logfile" &' ; # send output to logfile
fi
fi)
Overall, it's exec this>there
everywhere.
#!/bin/bash
my_function() {
local pid_file=$1; logfile=$2
local tee_output=0
if [ "$3" = "tee" ] ; then
tee_output=1
shift
fi
cmd=("${@:3}")
{
echo "executing ${cmd[@]}"
if [[ "$logfile" = "NO_LOG" ]]; then
exec 1>&3 2>&4
else
if [ "$tee_output" = "1" ] ; then
exec 1>&3 2>&4
exec 1> >(tee "$logfile")
else
exec >>"$logfile"
fi
fi
echo "$BASHPID" > "$pid_file"
exec "${cmd[@]}"
} >>"script_output.log" 2>&1
}
exec 3>&1 4>&2
my_function cmd.pid output.log echo hi
Also, service managers is an old topic. Consider just using systemd
or systemd-run
nowadays.