A growing collection of scripts and headers for your bash scripts.
Or with a file (not totally secure, race conditions may still happen though unlikely):
''
LOCKFILE=/var/lock/$(basename $0).lock
[ -f $LOCKFILE ] && exit 0
trap "{ rc=$?; rm -f $LOCKFILE ; exit $rc; }" EXIT
touch $LOCKFILE
...
''
Via a safe, locking mechanism (see ''man flock''):
''
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
''
With an additional timeout (lock is overridden after a while):
''
LOCK_FILE="/var/run/$(basename $0).pid"
LOCK_TIMEOUT=10
test $(( $(date +%s) - $(stat -c %Y "$LOCK_FILE" 2>/dev/null||echo 0) )) -ge "$LOCK_TIMEOUT" && rm -f "$LOCK_FILE" # remove stale lock
( set -o noclobber; echo "$$" > "$LOCK_FILE") 2> /dev/null || exit 1
trap "{ rc=\$?; rm -f '$LOCK_FILE'; exit \$rc; }" EXIT
''
find /sys/bus/usb/devices/usb*/ -name tty|sed 's|.*\(tty[^/]\+[0-9]\).*|\1|'
''
''
sudo apt install speedtest-cli
speedtest-cli
''
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.
Note: ''pgrep -af 'mqtt_watch.sh /solar/watts 5' '' is interesting to match a script with its arguments.
Or with a file (not totally secure, race conditions may still happen though unlikely):
''
LOCKFILE=/var/lock/$(basename $0).lock
[ -f $LOCKFILE ] && exit 0
trap "{ rc=$?; rm -f $LOCKFILE ; exit $rc; }" EXIT
touch $LOCKFILE
...
''
Via a safe, locking mechanism (see ''man flock''):
''
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
''
With an additional timeout (lock is overridden after a while):
''
LOCK_FILE="/var/run/$(basename $0).pid"
LOCK_TIMEOUT=10
test $(( $(date +%s) - $(stat -c %Y "$LOCK_FILE" 2>/dev/null||echo 0) )) -ge "$LOCK_TIMEOUT" && rm -f "$LOCK_FILE" # remove stale lock
( set -o noclobber; echo "$$" > "$LOCK_FILE") 2> /dev/null || exit 1
trap "{ rc=\$?; rm -f '$LOCK_FILE'; exit \$rc; }" EXIT
''
In case you would better wait for the lock than exit the script, you can loop on lock creation: ''while ! ( set -o noclobber; echo "$$" > "$LOCK_FILE") 2> /dev/null; do echo '(waiting for the lock)'; sleep 0.1; done'' (note that this would not enforce the timeout).
In case you would better wait for the lock than exit the script, you can loop on lock creation: ''while ! ( set -o noclobber; echo "$$" > "$LOCK_FILE") 2> /dev/null; do echo '(waiting for the lock)'; sleep 0.1; done'' (note that this would not enforce the timeout).
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 )"
''
Re-run a script as root if it was not called with sudo
At the start of the script, just add:
''
[ "$UID" -ne 0 ] && exec sudo "$0" "$@"
''
Automatically manage cronjob additions and removal of commands
Super quick backup of a file thanks to bash
''
cp /etc/rssh.{conf,original}
''
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 with leadging zeroes (e.g. to build a timelapse)
This works by extracting the number in their name (bashism ''${f//[!0-9]/}'' removes all non-digit), then add non-significant leading zeros to them:
''
for f in * .jpg; do mv "$f" /tmp/$(printf "%05d" ${f//[!0-9]/}).jpeg; done
''
Bash process substitution
This usual case:
''
sort file1 | uniq >tmp1
sort file2 | uniq >tmp2
diff tmp1 tmp2
''
Is better done with process substitution (no temporary file, no subshell, not even pipes):
''
diff <(sort file1|uniq) <(sort file2|uniq)
''
How it works is ''<(...)'' is replaced by a ''/dev/fd'' file descriptor as if it was a file (ref.)
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|'
''
Check ethernet bandwith
''sudo apt install speedtest-cli
speedtest-cli
''
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
''
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 via an argument as above, or through a pipe as below. Say you stored a timestamp with ''date +'%Y-%m-%d %H:%M' > last.txt''. Then:
The second and third very bash-specific line in the script makes it possible to pass the date via an argument as above, or through a pipe as below. 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
''
line="Something to log"
sed -ni "1s/^/$log\n/;500q;p" "$lf"
Say you have this file /tmp/test.ini to parse:
''
# Some comment
AA=da fook
BB=ya ' laa
CC=zarma $(ls)
DD_EE=0
EE=
''
You can parse it safely with this script to generate the respective variables
''
#!/bin/bash
k="$(echo $line|cut -d= -f1)"
v="$(echo $line|cut -d= -f2-)"
[[ $k =~ ^[A-Z_]+$ ]] && export $prefix$k="$v"
done < <(cat /tmp/test.ini)
echo BB=$SAFE_BB
echo CC=$SAFE_CC
# Result is:
# BB=ya ' laa
# CC=zarma $(ls)
''
Without ''$prefix'' set, make sure you do not allow variables in the left colum like PATH or LD...
''
tr -cd '\11\12\15\40-\176'
''
Add a line to a reverse, while keeping under 500 lines
''line="Something to log"
sed -ni "1s/^/$log\n/;500q;p" "$lf"
''
Robust parsing of a key = value ini file:
We want to set variables from a two-column file, without the risk that bash interprets the value (so the value can really be anything)
Say you have this file /tmp/test.ini to parse:
''
# Some comment
AA=da fook
BB=ya ' laa
CC=zarma $(ls)
DD_EE=0
EE=
''
You can parse it safely with this script to generate the respective variables
''
#!/bin/bash
prefix=SAFE_
while read -r line; dok="$(echo $line|cut -d= -f1)"
v="$(echo $line|cut -d= -f2-)"
[[ $k =~ ^[A-Z_]+$ ]] && export $prefix$k="$v"
done < <(cat /tmp/test.ini)
echo BB=$SAFE_BB
echo CC=$SAFE_CC
# Result is:
# BB=ya ' laa
# CC=zarma $(ls)
''
Without ''$prefix'' set, make sure you do not allow variables in the left colum like PATH or LD...
Filter out non printable charcacters of a stream
Eg. when ''syslog'' gets corrupted with binary characters and many tools claim the file is binary:''
tr -cd '\11\12\15\40-\176'
''