First, if the script is run by a system daemon and that daemon is running with root privileges, you do not need to use sudo
. This includes init
(and systemd
), which includes rc.local
. If that daemon is not running with root privileges, then sudo
will not work unless /etc/sudoers
is configured to allow such (and without a password). Raspbian users may be confused by this since the pi
user is allowed to do anything by default (and if you look in /etc/sudoers
you will see how that is accomplished).
Next, you can capture output from any bash
script, or any set of commands inside a bash script, by executing them in a subshell like this:1
(
/bin/foo on 3
sudo bar a
) &> /var/log/myTestLog.txt
The ()
indicates a subshell. All output from anything inside this is being redirected to a /var/log/myTestLog.txt
file. A few notes:
&>
is a bashism, so if the script is executed via a shebang on the first line, it should be #!/bin/bash
, not just /bin/sh
. "Bashisms" work only in the bash
shell.
This includes /etc/rc.local
, which by default uses /bin/sh
(ie., yes, you can safely change that to /bin/bash
).
/var/log
requires root privileges to write to. If the process does not have such, use or create a directory you know it can. When in doubt, if you can test this without having to shutdown or reboot the system, use /tmp
, which is world writable (i.e., by anyone). However /tmp
does not persist across boots. It is also a small, RAM based partition, so do not write gigs of data to it. It is not your SD card [actually on current versions of Raspbian it is, but don't count on this in practice].
&>
will overwrite anything in myTestLog.txt
. If instead you want to append to a existing log, which might be a good idea for debugging purposes, use &>>
. You could then add a command to the beginning of that subshell like this:
echo Starting $(date)
To separate the information from each run. If you're not sure what this does, try on the command line.
This last point is a good illustration of something you can do with regard to commands that don't output anything -- but most of them do if you include, e.g., -v
for "verbose". Beware for some commands -v
means "print version information". Have a look in the man page for the command to be sure if and how this will work (some commands also use a different switch than -v
).
By convention, commands also return a value of 0 when complete. This is sometimes called the "exit status" and you do not normally see it, but the shell will show you with echo $?
. Try
ls /
echo $?
ls /nonexistantdir
echo $?
You'll get 0 and 2. If you then look in the man page for ls
under "Exit status", you'll see the rather unspecific, cryptic:
2 if serious trouble (e.g., cannot access command-line argument).
Which may or may not be better than nothing, but there you go.
At the very least, this indicates the command failed for some reason. The exit status also allows you to do things like this:
/bin/foo && sudo bar
The &&
in this case means "if the first command succeeds", presuming the first command uses the convention of returning 0 (which is why they usually do). If /bin/foo
does not work, cannot be found, etc., then sudo bar
will never happen.
Using a combination of logging messages and conditional execution (&&
) should get you much closer to figuring out the problem, or at least getting information that might be useful to others in helping you solve the problem. Without that, the most anyone else can often do is guess.
1. You can accomplish the same output redirection for an entire script from the inside by using:
exec &> /var/log/myTestLog.txt
At the top (or anywhere, and it will apply to everything subsequent).
U&L
. I misread the title and would suggest "Logging the output of a system script for debugging" would make the purpose clearer. Also my brain freezes over when I read thesefoo
bar
examples, I prefer something which looks more real world. I am reluctant to edit any post, so will leave this to you if you think it can be improved. – Milliways Feb 03 '16 at 22:44