Time individual statements in bash

Sometimes the 1000+ line bash script you inherited at work takes 3 hours to complete and you’re not sure where the time is being spent. StackOverflow has some good answers on this topic:

http://stackoverflow.com/questions/5014823/how-to-profile-a-bash-shell-script
http://stackoverflow.com/questions/18039751/how-to-debug-a-bash-script-and-get-execution-time-per-command

The simplest one that gives me the most value for the least effort (imo) is:

PS4='+[${SECONDS}s][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
#!/bin/bash

PS4='+[${SECONDS}s][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -x

echo 1
sleep 1
echo 2
sleep 2
echo 3

This produces the following output:

joao@home:~> ./timings.sh
+[0s][./timings.sh:7]: echo 1
1
+[0s][./timings.sh:8]: sleep 1
+[1s][./timings.sh:9]: echo 2
2
+[1s][./timings.sh:10]: sleep 2
+[3s][./timings.sh:11]: echo 3
3

Happy bash profiling !

Time individual statements in bash

qemu disk format autodetection

Lets say you use qemu like this:

sudo qemu-system-x86_64 \
    -hda system.raw	\
    -hda data.raw

In recent versions of qemu, you might see this error message:

WARNING: Image format was not specified for 'system.raw' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.

To avoid the warning and remove the restriction on block 0 write operations, do what the error message suggests and explicitly set the disk file format to raw, ie:

sudo qemu-system-x86_64 \
    -drive file=system.raw,format=raw,index=0,media=disk \
    -drive file=data.raw,format=raw,index=1,media=disk

Happy qemuing!

qemu disk format autodetection

Redirect STDOUT/STDERR

Sometimes you want to redirect your shell script’s STDOUT/STDERR to a log file. This is pretty simple to do, ie:

./myscript.sh &> output.log

But sometimes you want to do the redirect inside the script itself ( ie, maybe redirecting is conditional, or maybe the file name is conditional on something only the script knows about)


#!/bin/bash

exec >> output.log
exec 2>&1

>&2 echo "This was printed to stderr"
echo "This was printed to stdout"

Or if you want to write to both a file and the terminal:

#!/bin/bash

exec 1> >(tee -a output.log)
exec 2>&1

>&2 echo "This was printed to stderr"
echo "This was printed to stdout"

Stackoverflow has other ways to do it:

Redirect STDOUT/STDERR