Sunday, November 29, 2015

Small and useful bash scripts

A growing collection of scripts and headers for your bash scripts.

Check and exit if a script is already running

This is to prevent multiple running instances of the same script:
''
test "$(pidof -x "$(basename $0))" != $$ && exit
# or (bash only and protected against spaces in paths):
test "$(pidof -x "$(basename $0))" != $$ && exit
''

Note: ''pgrep -af 'mqtt_watch.sh /solar/watts 5' '' is interesting to match a script with its arguments.

Get the full directory name of the script

This works no matter where it is being called from:
''
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
''

Automatically manage cronjob additions and removal of commands

Use command lines to add or remove scheduled jobs in your ''crontab'':
''
croncmd="/home/me/myfunction start 2> /home/me/myfunction/cron_errors < /dev/null"
cronjob="0 0 * * * $croncmd"
# Add
( crontab -l | grep -v "$croncmd" ; echo "$cronjob" ) | crontab -
# Remove
( crontab -l | grep -v "$croncmd" ) | crontab -
''

Use pv to get a progress bar with dd

''pv'' can be used in many contexts to provide a progress bar:

''
dd bs=4M if=image.dd | pv | dd of=/dev/sdz
''

Re-index a set of files (typically images, to build a timelapse)

This works by extracting the number in their name and add non-significant leading zeros (bash)
''
for f in ​*​.jpg; do mv "$f" /tmp/$(printf "%05d" ${f//[!0-9]/}).jpeg; done
''

Ubuntu: find the biggest installed packages

''
dpkg-query --show --showformat='${Package;-50}\t${Installed-Size}\n' | sort -k 2 -n | grep -v deinstall | awk '{printf "%.3f MB \t %s\n", $2/(1024), $1}' | tail -50
''
Then after removing it, ''apt-get clean'' will also purge the package cache (a good thing to free some harddrive space)

Find your serial port attached to USB

This returns devices like ttyUSB (or ttyACM):
''
find /sys/bus/usb/devices/usb*/ -name tty|sed 's|.*\(tty[^/]\+[0-9]\).*|\1|'
''

Compute date difference with flexible parametrization (very bashic!)

Here is ''date_diff.sh'':
''
#!/bin/bash
set -- "${1:-$(</dev/stdin)}" "${@:2}"
[[ -f "$1" ]] && set -- "$(<$1)" "${@:2}"
echo $( date -d@$(( ( $(date +'%s') - $(date -d "$1" '+%s') ) )) +%s ) 3600 / p | dc
''

Then:
''
root:~# ./date_diff.sh "2016-08-09 06:03"
27
''
This is twenty-seven hours from now to the recorded date.

The second and third very bash-specific line in the script makes it possible to pass the date in other ways. Say you stored a timestamp with ''date +'%Y-%m-%d %H:%M' > last.txt''. Then:

''
root:~# cat last.txt | ./date_diff.sh 
27
root:~# ./date_diff.sh last.txt 
27
''