├── .gitignore ├── README.md ├── directory-changes-monitor ├── README └── monitor.sh ├── dumpstart ├── README └── dumpstart.sh ├── google-drive-upload ├── README └── upload.sh ├── google-oauth2 ├── README └── google-oauth2.sh ├── log-monitor-events ├── README └── monitor.sh └── wordpress-watch ├── README └── watch.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bash-utils 2 | ========== 3 | 4 | A collection of pocket-size bash script utilities. Very raw, usually thrown together in minutes, lots of room for improvement. 5 | -------------------------------------------------------------------------------- /directory-changes-monitor/README: -------------------------------------------------------------------------------- 1 | A simple file changes monitor 2 | usage: monitor.sh directory "command" 3 | 4 | examples: 5 | ./monitor /path/to/src "restart-server" 6 | -------------------------------------------------------------------------------- /directory-changes-monitor/monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # A simple file changes monitor 4 | # usage: monitor.sh dir command 5 | 6 | A=`find "$1" -printf '%t' 2>/dev/null | md5sum`; 7 | while true; do 8 | B=`find "$1" -printf '%t' 2>/dev/null | md5sum`; 9 | if [ "$A" != "$B" ]; then 10 | echo "Detected change, doing: $2" 11 | eval $2 12 | A=$B 13 | fi 14 | sleep 1 15 | done 16 | -------------------------------------------------------------------------------- /dumpstart/README: -------------------------------------------------------------------------------- 1 | Simply restarting a service (a.k.a "have you tried switching it off and on again") is not a good solution. This little script generates postmortems for later analysis before restarting. 2 | 3 | Set `PROCESS`, `SERVICE` and `LOGFILE` to do a process/thread coredump, a logfile dump and a service restart. These can be used separately. Example: 4 | 5 | PROCESS=nginx SERVICE=nginx LOGFILE="/var/log/nginx/error.log /var/log/access.log" ./dumpstart.sh 6 | PROCESS=mysqld SERVICE=mysql LOGFILE=/var/log/mysql.err ./dumpstart.sh 7 | PROCESS=php5-fpm SERVICE=php5-fpm LOGFILE=/var/log/php5-fpm.log ./dumpstart.sh 8 | -------------------------------------------------------------------------------- /dumpstart/dumpstart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # By default we dump to a directory with the current time 4 | # this can be overridden by setting the UID envvar 5 | DUMPDIR=${DUMPDIR:-"~/.postmortems/$(date +%Y%m%d%H%M%S)"} 6 | 7 | # Read PROCESS, SERVICE and LOGFILE envvars 8 | # and do dump, restart and read log respectively 9 | # These can be called separately. 10 | 11 | # Dump process memory 12 | if [ ! -z "$PROCESS" ]; then 13 | mkdir -p $DUMPDIR 14 | 15 | # Coredump processes and threads 16 | for pid in $(pidof $PROCESS); do 17 | for tid in $(ls /proc/$pid/task); do 18 | gcore -o $DUMPDIR/$PROCESS.$tid.$(date +%Y%m%d%H%M%S).core $tid 19 | done; 20 | done; 21 | fi; 22 | 23 | # Dump logfiles (can be a space-delimited list of files) 24 | if [ ! -z "$LOGFILE" ]; then 25 | mkdir -p $DUMPDIR 26 | 27 | for l in $LOGFILE; do 28 | cp $l $DUMPDIR/$PROCESS.$(date +%Y%m%d%H%M%S).$(basename $l) 29 | done; 30 | fi; 31 | 32 | # Restart service 33 | if [ ! -z "$SERVICE" ]; then 34 | service $SERVICE restart 35 | fi; 36 | -------------------------------------------------------------------------------- /google-drive-upload/README: -------------------------------------------------------------------------------- 1 | Allows one to upload a file to Google Drive using nothing but cURL. 2 | 3 | Usage: 4 | upload.sh [title] [path] [mime] 5 | 6 | The `path` argument has to be an ID, not a name. 7 | The ID of a folder on Google Drive can be retrieved from its URL. 8 | Always double check your uploads, since corruption may happen. 9 | -------------------------------------------------------------------------------- /google-drive-upload/upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Upload a file to Google Drive 4 | # 5 | # Usage: upload.sh [title] [path] [mime] 6 | 7 | set -e 8 | 9 | ACCESS_TOKEN=$1 10 | BOUNDARY=`cat /dev/urandom | head -c 16 | xxd -ps` 11 | MIME_TYPE=${5:-"application/octet-stream"} 12 | 13 | ( echo -en "--$BOUNDARY\nContent-Type: application/json; charset=UTF-8\n\n{ \"title\": \"$3\", \"parents\": [ { \"id\": \"$4\" } ] }\n\n--$BOUNDARY\nContent-Type: $MIME_TYPE\n\n" \ 14 | && cat $2 && echo -en "\n\n--$BOUNDARY--\n" ) \ 15 | | curl -v "https://www.googleapis.com/upload/drive/v2/files/?uploadType=multipart" \ 16 | --header "Authorization: Bearer $ACCESS_TOKEN" \ 17 | --header "Content-Type: multipart/related; boundary=\"$BOUNDARY\"" \ 18 | --data-binary "@-" 19 | -------------------------------------------------------------------------------- /google-oauth2/README: -------------------------------------------------------------------------------- 1 | A simple cURL OAuth2 authenticator 2 | 3 | Depends on Python's built-in json module to prettify output 4 | 5 | Usage: 6 | `./google-oauth2.sh create` - authenticates a user 7 | `./google-oauth2.sh refresh` - gets a new token 8 | 9 | Set `CLIENT_ID` and `CLIENT_SECRET` and `SCOPE` 10 | -------------------------------------------------------------------------------- /google-oauth2/google-oauth2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # A simple cURL OAuth2 authenticator 4 | # depends on Python's built-in json module to prettify output 5 | # 6 | # Usage: 7 | # ./google-oauth2.sh create - authenticates a user 8 | # ./google-oauth2.sh refresh - gets a new token 9 | # 10 | # Set CLIENT_ID and CLIENT_SECRET and SCOPE 11 | 12 | CLIENT_ID="" 13 | CLIENT_SECRET="" 14 | SCOPE=${SCOPE:-"https://docs.google.com/feeds"} 15 | 16 | set -e 17 | 18 | if [ "$1" == "create" ]; then 19 | RESPONSE=`curl --silent "https://accounts.google.com/o/oauth2/device/code" --data "client_id=$CLIENT_ID&scope=$SCOPE"` 20 | DEVICE_CODE=`echo "$RESPONSE" | python -mjson.tool | grep -oP 'device_code"\s*:\s*"\K(.*)"' | sed 's/"//'` 21 | USER_CODE=`echo "$RESPONSE" | python -mjson.tool | grep -oP 'user_code"\s*:\s*"\K(.*)"' | sed 's/"//'` 22 | URL=`echo "$RESPONSE" | python -mjson.tool | grep -oP 'verification_url"\s*:\s*"\K(.*)"' | sed 's/"//'` 23 | 24 | echo -n "Go to $URL and enter $USER_CODE to grant access to this application. Hit enter when done..." 25 | read 26 | 27 | RESPONSE=`curl --silent "https://accounts.google.com/o/oauth2/token" --data "client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&code=$DEVICE_CODE&grant_type=http://oauth.net/grant_type/device/1.0"` 28 | 29 | ACCESS_TOKEN=`echo "$RESPONSE" | python -mjson.tool | grep -oP 'access_token"\s*:\s*"\K(.*)"' | sed 's/"//'` 30 | REFRESH_TOKEN=`echo "$RESPONSE" | python -mjson.tool | grep -oP 'refresh_token"\s*:\s*"\K(.*)"' | sed 's/"//'` 31 | 32 | echo "Access Token: $ACCESS_TOKEN" 33 | echo "Refresh Token: $REFRESH_TOKEN" 34 | elif [ "$1" == "refresh" ]; then 35 | REFRESH_TOKEN=$2 36 | RESPONSE=`curl --silent "https://accounts.google.com/o/oauth2/token" --data "client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&refresh_token=$REFRESH_TOKEN&grant_type=refresh_token"` 37 | 38 | ACCESS_TOKEN=`echo $RESPONSE | python -mjson.tool | grep -oP 'access_token"\s*:\s*"\K(.*)"' | sed 's/"//'` 39 | 40 | echo "Access Token: $ACCESS_TOKEN" 41 | fi 42 | -------------------------------------------------------------------------------- /log-monitor-events/README: -------------------------------------------------------------------------------- 1 | Monitor streams for specific byte sequences and react 2 | usage: monitor.sh keyword command 3 | 4 | examples: 5 | tail -f /var/log/access.log | ./monitor.sh "admin" "./alertme.sh" 6 | ssh me@server "tail -f /var/log/error.log" | ./monitor.sh "invalid" 'echo "Alert!" | mail ...' 7 | -------------------------------------------------------------------------------- /log-monitor-events/monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Monitor streams for specific byte sequences and react 4 | # usage: monitor.sh keyword command 5 | 6 | while read line; do 7 | line=`echo -n "$line" | grep -i "$1"` 8 | if [ -n "$line" ]; then 9 | eval $2 10 | fi 11 | done 12 | -------------------------------------------------------------------------------- /wordpress-watch/README: -------------------------------------------------------------------------------- 1 | WordPress now uses Grunt to build the core JavaScript files for for unit tests, etc. I hate this. 2 | `grunt build` is slow (30+ seconds) and pointless for a single changed PHP file. This watch script copies the modified file and runs phpunit with the needed arguments. Super fast, clear watch code. 3 | -------------------------------------------------------------------------------- /wordpress-watch/watch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | while true; do 3 | modified=$(inotifywait --format '%w%f' --exclude '.swp' -e modify src/**/) 4 | cp -v "$modified" $(echo "$modified" | sed 's/^src/build/') 5 | phpunit --no-coverage $@ 6 | done 7 | --------------------------------------------------------------------------------