Skip to content

Instantly share code, notes, and snippets.

@AlexAtkinson
Last active October 25, 2024 20:00
Show Gist options
  • Save AlexAtkinson/38b618f0aa42a1fd296af8e4902e368a to your computer and use it in GitHub Desktop.
Save AlexAtkinson/38b618f0aa42a1fd296af8e4902e368a to your computer and use it in GitHub Desktop.
BASH Cheatsheet

CONTENTS

Introduction

Some commands that I constantly revisit. Much of this is BASH related.

Basics & Gotchas

A few concepts/artifacts that confuse, or limit capability in outage.

BASH: End of Options

Many builtin commands accept options preceded by '-' and treat '--' as specifically flagging the end of options, allowing for strings which may include a prefix of '-' to be handled as intended. For example: grep -v 'foo' -- -v.

Note the particular usefulness in scenarios where the leading character is unknown, and may be a '-/+'. For Example: rm -f -- *.*, or cmd | xargs rm -f --.

REF: 4 Shell Builtin Commands

Usability

.bashrc

Set CLI Editors to VIM from nano

# Change default systemctl editor
# NOTE: Must also add to sudoers (in the env_keep section) with 'sudo visudo': `Defaults  env_keep += "SYSTEMD_EDITOR"`
export SYSTEMD_EDITOR=vim

# Change editor to VIM
export EDITOR=vim

# Make visudo use vim with sudo
alias visudo='sudo EDITOR=vim visudo'
    NOTE: You could add to sudoers (in the env_keep section) with 'sudo visudo': `Defaults  env_keep += "EDITOR"`

Simple Timer

alias timer-start='timer_start=$SECONDS'
alias timer-duration='if [[ -n $timer_start ]]; then timer_now=$SECONDS; duration=$(( timer_now - timer_start )); echo $duration seconds; unset timer_now duration; else echo timer not running; fi'
alias timer-stop='timer-duration; unset timer_start'

Better Timer

alias timer-start='timer_start=$SECONDS'
function timer-handler() {
  if [[ -n $timer_start ]]; then
    timer_now=$SECONDS
    timer_duration=$(( timer_now - timer_start ))
  else
    echo "timer not started"
    exit 1
  fi
  timer_output="$timer_duration seconds"
  if [[ $1 -eq 8601 ]]; then
    timer_duration_hours=$(( timer_duration/3600 ))
    timer_duration_minutes=$(( timer_duration%3600 / 60 ))
    timer_duration_seconds=$(( timer_duration%60%3600 ))
    timer_duration="$(printf "%02d" $timer_duration_hours):$(printf "%02d" $timer_duration_minutes):$(printf "%02d" $timer_duration_seconds)"
    timer_output="$timer_duration"
  fi
}
function timer-duration() {
 timer-handler $1
 echo $timer_output
 unset timer_now timer_duration timer_output
}
alias timer-stop='timer-duration $1; unset timer_start'

PW Generators

Option 1

alias genpass_alnumspec='pin1="!@#$%^&*()<>[]{}|_+-="; pin2=$(openssl rand -base64 128 | fold -w 20 | head -n 1); pout1=$(openssl rand -base64 128 | tr -dc 'a-zA-Z' | fold -w 1 | head -n 1); pout2=$(echo "${pin1}${pin2}" | fold -w 1 | shuf | tr -d "\n" | fold -w 19 | head -n 1); echo "${pout1}${pout2}"'
alias genpass_alnumspec_x4='printf "%s\n" $(genpass_alnumspec)$(genpass_alnumspec)$(genpass_alnumspec)$(genpass_alnumspec)'
alias genpass_alnum='openssl rand -base64 128 | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1'
alias genpass_alnum_x4='printf "%s\n" $(genpass_alnum)$(genpass_alnum)$(genpass_alnum)$(genpass_alnum)'

Option 2

alias genpass_alnumspec='openssl rand -base64 32 | head -c 16 ; echo '''
alias genpass_alnum="openssl rand -base64 32 | tr -d \"\!@#$%^\&*()_\+\-\=\[]\{}|\\\/\'\" | head -c 16 ; echo ''"

Bytes to human readable

function bytesToHumanReadable() {
    if test -n "$1"; then$
        input="$@"
    elif test ! -t 0; then
        input="$(</dev/stdin)"
    fi
    local i=${input:-0} d="" s=0 S=("Bytes" "KiB" "MiB" "GiB" "TiB" "PiB" "EiB" "YiB" "ZiB")
    while ((i > 1024 && s < ${#S[@]}-1)); do
        printf -v d ".%02d" $((i % 1024 * 100 / 1024))
        i=$((i / 1024))
        s=$((s + 1))
    done
    echo "$i$d ${S[$s]}"
}

Awesome Headers

# Prints a section header.
#
# Features
#   - Autosizes to terminal if $width -gt $COLUMNS
#   - Specifying width as 4000 works...
#   - Adjust first two sanities for stricter usage
#     * Currently sets width to half terminal width
#     * Currently rounds down odd to even width automatically
#
# Usage:
#   printSectionHeader <width> <message>
#
# Examples:
#   printSectionHeader Hello World!
#   printSectionHeader 40 Hello World!
#
# Output:
#     # ------------------------------------ #
#     # //////////////////////////////////// #
#     # /////////// Hello World! /////////// #
#     # //////////////////////////////////// #
#     # ------------------------------------ #
#
function printSectionHeader() {
    local width=$1
    local txt="${@:2}"
    if [[ ! $width =~ ^[0-9]+$ ]]; then
        #echo "ERROR: First argument must specify the width as an even number (int)."
        #return 1
        width=$((COLUMNS/2))
        local txt="$*"
    fi
    if [[ $((width%2)) -eq 1 ]]; then
        #echo "ERROR: The width must be an even number (int)."
        #return 1
        width=$(($width-($width%2)))
    fi
    local fill=$(($width-4))
    local txt_length=${#txt}
    local min_width=$((txt_length+8))
    if [[ $width -lt $min_width ]]; then
        echo "ERROR: Minimum width for text length ($txt_length) is $min_width."
        return 1
    fi
    local padding=8
    local cols=$((COLUMNS - (COLUMNS % 2)))
    [[ $fill -gt $((cols-padding)) ]] && fill=$((cols-$((padding/2))))
    local fill_width="$((cols-cols-fill))"
    local half_fill_width=$(( ((((fill_width/2))+((padding/ 2))))+$((txt_length/2))-1 ))
    local fill="$(printf '%*s' "${fill_width}" | tr ' ' \-)"
    local inside_fill="$(printf '%*s' "$((fill_width))" | tr ' ' \/)"
    local inside_half_fill="$(printf '%*s' "$((half_fill_width -2))" | tr ' ' \/)"
    printf "# "; printf '%s' "${fill}"; printf " #\n"
    printf "# "; printf '%s' "${inside_fill}"; printf " #\n"
    printf "# "; printf '%s' "${inside_half_fill}"
    printf "\e[01;39m $txt \e[0m"
    [[ $((txt_length%2)) -eq 1 ]] && local inside_half_fill="$(printf '%*s' "$((half_fill_width -1))" | tr ' ' \/)"
    printf '%s' "${inside_half_fill}"; printf " #\n"
    printf "# "; printf '%s' "${inside_fill}"; printf " #\n"
    printf "# "; printf '%s' "${fill}"; printf " #\n"
}

Watch Colorizer

alias watch='watch --color'

Tmux Control

alias tmuxn='tmux new-session -s $1'
alias tmuxk='tmux kill-session -t $1'
alias tmuxa='tmux attach-session -t $1'
alias tmuxl='tmux ls'
function tmuxwhereami() {
  if [[ -n $TMUX ]]; then
    echo -e "\e[01;39mINFO\e[0m: Current TMUX session: $(tmux display-message -p "#S")"
  else
    echo -e "\e[01;31mERROR\e[0m: Not in a TMUX session."
  fi
}

Network Tools

alias digna='dig +noall +answer $1'
alias digns='dig NS +noall +answer $1'
alias digsoa='dig SOA +noall +answer $1'
function digsoahost() {
  digsoa | awk '{gsub(/.$/,"",$5); print $5}'
}
function digttl() {
  dig +noall +answer $1 @$(digns $1 | awk 'NR==1 {print $5}') | awk 'NR==1 {print $2}'
}
function nslookupsoa() {
  nslookup $1 $(digsoahost $1)
}
function geoip_lookup() {
  curl -sS "http://api.ipstack.com/$1?access_key=<API key>&output=json&fields=country_code,city" | jq -r '"\(.city), \(.country_code)"'
}

function constat() {
  # Requires net-tools procps
  tmpfile='/tmp/connections.out'
  netstat -antu > $tmpfile
  printf "CONNECTION COUNTS (UDP,TCP):\n"
  printf -- "-----------------\n"
  for i in CLOSE_WAIT CLOSED ESTABLISHED FIN_WAIT_1 FIN_WAIT_2 LISTEN SYN_RECEIVED SYN_SEND TIME_WAIT UDP ; do
            echo -e "${i}: $(grep -ci ${i} ${tmpfile})"
    done
    echo -e "TOTAL: $(grep -c ^ ${tmpfile})"
    #rm -f $tmpfile
}

SSH Aliasing

# alias sshto{env}{vpc}='ssh -i ~/.ssh/bastion-host-pem-key.pem [email protected]'
alias sshtodevdproc='ssh -i ~/.ssh/123412341234-us-east-1-dev-dbproc-public.pem [email protected]'

Git

alias git-commit-tree='git log --graph --pretty=oneline --abbrev-commit'
alias git-commit-grep='git log --oneline | grep $1'
function gitc() { git commit -m "DEVOPS-00: $*" ;}
function gitcp() { git commit -m "DEVOPS-00: $*" ; git push;}
function gitce() { git commit --allow-empty -m "DEVOPS-00: $*";}
function gitcep() { git commit --allow-empty -m "DEVOPS-00: $*"; git push;}
function git-diff() {
  git difftool -y -x sdiff HEAD^ $1 | \
    pygmentize | \
    less -R
}
alias find-the-empty-tree='the_empty_tree=$(git hash-object -t tree /dev/null)'
  # Use: In a git repo, run 'find-the-empty-tree' to set the var 'the_empty_tree'

Docker

alias di='docker images | grep -v "^<none>"'
alias digrep='di | grep $1'
alias docker-ps='docker ps --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}"'
function docker-ps-watch() {
  watch -n2 'docker ps --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}"'
}

Unicode Interpretation

[Ctrl+Shift+u] will launch the unicode intrepretor. Uing this shortcut will cause an underlined 'u' to display. Typing the code for a character or symbol and hitting enter will then populate it.

Example: Hitting '[Ctrl+Shift+u]b5' will cause a micor 'µ' symbol to populate.

NOTE: In some text editors, such as Sublime, this is achieved with '[Ctrl+Shift_u]b5[Space]'.

Keyboard Cursor Rates

The default settings for keyboard repeats is always exceedingly limiting. This is how to get the most out of your keyboard.

Note: It is typical for the local settings to override the settings of a remote. For example, settings on a server will not present via ssh.

Mac

Get current settings.

defaults read -g InitialKeyRepeat     # normal minimum is 15 (225 ms)
defaults read -g KeyRepeat            # normal minimum is 2 (30 ms)

Go beyond the System Preferences slider WARNING: Only change InitialKeyRepeat as follows if you're a madman, as this can present issues when inputting your password at login.

defaults write -g InitialKeyRepeat -int 10
defaults write -g KeyRepeat -int 1

Linux CLI

Set the initial delay to 150ms, and the repeat rate to 24 characters per second (cps).

sudo kbdrate -d 150 -r 24

Reset to defaults.

sudo kbdrate

Linux X

The X is for X, as in the X Window System display server (GUI).

Get current settings.

xset -q

Set the inital key delay to 200ms, and the repeat rate to 70ms.

xset r rate 200 70

Reset to defaults.

xset r rate

Mac Fixes

Linuxify

https://github.com/shinokada/macgnu https://github.com/fabiomaia/linuxify

Keyboard Rates

See Mac in Keyboard Cursor Rates for this one.

iTerm

Disable printing of control characters when re-focuing on iTerm.

Profile Preferences > Advanced Tab > Enable 'Apps may turn on Focus Reporting'

Enable key repeats. This disables the popup that shows accents, etc., on long press.

defaults write -g ApplePressAndHoldEnabled -bool false

Formatting

COLORS

Foreground Colors

39  Default foreground color
30  Black
31  Red
32  Green
33  Yellow
34  Blue
35  Magenta
36  Cyan
37  Light gray
90  Dark gray
91  Light red
92  Light green
93  Light yellow
94  Light blue
95  Light magenta
96  Light cyan
97  White

Background Colors

49  Default background color
40  Black
41  Red
42  Green
43  Yellow
44  Blue
45  Magenta
46  Cyan
47  Light gray
100 Dark gray
101 Light red
102 Light green
103 Light yellow
104 Light blue
105 Light magenta
106 Light cyan
107 White

Additional Formatting

0           Reset all attributes
1   21      Bold
2   22      Dim
4   24      Underlined
5   25      Blink
7   27      Reverse (Invert forground/background)
8   28      Hidden (Useful for passwords)

Syslog Severity Levels

Bold, Color, and then RESET ALL (RFC5424)

echo -e "\nColorized Severity (rfc5424)"                                            ;\
echo -e "\e[01;30;41mEMERGENCY\e[0m      : 0 - Bold BLACK test, RED background"     ;\
echo -e "\e[01;31;43mALERT\e[0m          : 1 - Bold RED text, YELLOW background"    ;\
echo -e "\e[01;97;41mCRITICAL\e[0m       : 2 - Bold WHITE text, RED background"     ;\
echo -e "\e[01;31mERROR\e[0m             : 3 - Bold RED text"                       ;\
echo -e "\e[01;33mWARNING\e[0m           : 4 - Bold YELLOW text"                    ;\
echo -e "\e[01;30;107mNOTICE\e[0m        : 5 - Bold BLACK text, WHITE background"   ;\
echo -e "\e[01;39mINFORMATIONAL\e[0m     : 6 - Bold WHITE text"                     ;\
echo -e "\e[01;32mSUCCESS\e[0m           : 6 - Bold GREEN text"                     ;\
echo -e "\e[01;97;46mDEBUG\e[0m          : 6 - Bold WHITE text, CYAN background\n"

Scripts

Truecolour Test

truecolour-test.sh prints a rainbow of colors across the terminal.

#!/bin/bash
# truecolour-test.sh
# Based on: https://gist.github.com/XVilka/8346728

awk -v term_cols="${width:-$(tput cols || echo 80)}" 'BEGIN{
    s="/\\";
    for (colnum = 0; colnum<term_cols; colnum++) {
        r = 255-(colnum*255/term_cols);
        g = (colnum*510/term_cols);
        b = (colnum*255/term_cols);
        if (g>255) g = 510-g;
        printf "\033[48;2;%d;%d;%dm", r,g,b;
        printf "\033[38;2;%d;%d;%dm", 255-r,255-g,255-b;
        printf "%s\033[0m", substr(s,colnum%2+1,1);
    }
    printf "\n";
}'

Optionally set a 'width' environmental variable. For example, span color across 10 lines.

(( w = $(tput cols) * 10 )); width=$w ./truecolour-test.sh

Terminal Colour Cheat Sheet

colours.sh prints a table with all the usable codes. See here for a suped-up version.

#!/bin/bash
# colours.sh
# http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html

T='gYw'   # The test text

echo -e "\n                 40m     41m     42m     43m\
     44m     45m     46m     47m";

for FGs in '    m' '   1m' '  30m' '1;30m' '  31m' '1;31m' '  32m' \
           '1;32m' '  33m' '1;33m' '  34m' '1;34m' '  35m' '1;35m' \
           '  36m' '1;36m' '  37m' '1;37m';
  do FG=${FGs// /}
  echo -en " $FGs \033[$FG  $T  "
  for BG in 40m 41m 42m 43m 44m 45m 46m 47m;
    do echo -en "$EINS \033[$FG\033[$BG  $T  \033[0m";
  done
  echo;
done
echo

BASH

Brace Expansion

🗒️ +(...) is part of extended globs, you need to enable them explicitly with shopt -s extglob 🗒️ expansions support glob -NOT- regex

https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Expansions https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Pattern-Matching

${var} Value of var, same as $var ${var,,} lowercase ${var^^} UPPERCASE ${#var} Returns the length in characters ${var-DEFAULT} If var not set, evaluate expression as $DEFAULT * ${var:-DEFAULT} If var not set OR null, evaluate expression as $DEFAULT * ${var=DEFAULT} If var not set, evaluate expression as $DEFAULT * ${var:=DEFAULT} If var not set, evaluate expression as $DEFAULT * ${var+OTHER} If var set, evaluate expression as $OTHER, otherwise as null string ${var:+OTHER} If var set, evaluate expression as $OTHER, otherwise as null string ${var?ERR_MSG} If var not set, print $ERR_MSG * ${var:?ERR_MSG} If var not set OR null, print $ERR_MSG * ${!varprefix*} Matches all previously declared variables beginning with varprefix (works with arrays) ${!varprefix@} Matches all previously declared variables beginning with varprefix (works with arrays)

shorted matching

longest matching

${var/foo/bar} Replace FIRST MATCH ${var/foo} DELETE first match ${var//foo} DELETE all matches ${var/%foo/bar} Replace SUFFIX ${var/%foo} DELETE SUFFIX ${var%%foo/bar} Replace LONG SUFFIX ${var/#foo/bar} Replace PREFIX ${var/#foo} DELETE PREFIX ${var##foo/bar} Replace LONG PREFIX ${var//foo/bar} Replace ALL instances of foo with bar

Datetime Format

2018 Update For Microsecond Accuracy

Timestamps to conform with RFC3339Micro, an internet profile of ISO8601, with microseconds formatted according to Section 6 of RFC5424. See References for more details. NOTE: Do NOT use nano, as this causes issues with syslog.

Examples: 1985-04-12T23:20:50.522299Z 1985-04-12T23:20:50.522299+0500

Variable:

If you know your server is in UTC+0000, you can use Z:

time=$(printf "$(date --utc +"%FT%T").$(printf $(($(date --utc +%s%N)/1000)) | cut -b11-16)Z")
echo $time

Or use this to ensure portability between timezones:

time=$(printf "$(date --utc +"%FT%T").$(printf $(($(date --utc +%s%N)/1000))$(date +"%z") | cut -b11-21)")
echo $time

Function:

If you know your server is in UTC+0000, you can use Z:

ts() { printf "$(date --utc +"%FT%T").$(printf $(($(date +%s%N)/1000)) | cut -b11-16)Z"; }
ts

Or use this to ensure portability between timezones:

ts() { printf "$(date --utc +"%FT%T").$(printf $(($(date --utc +%s%N)/1000))$(date +"%z") | cut -b11-21)"; }
ts

ISO8601 Basic

This can be used when accuracy to the microsecond is not required.

Examples: 2016-10-14T00:19:53.237Z 2016-10-14T00:19:53.237+0300

date --utc +"%FT%T.%3NZ"

Script Outputs

Script outputs can be controlled entirely by redirecting exec. HINT: Trigger with -s/S for silent handling.

#!/usr/bin/env bash

echo hi

exec &> /dev/null

echo bye
bad-cmd
echo secret hi > /dev/tty

exec > /dev/tty
echo hi again

Discrete Redirects

Commands can have their output redirected as follows:

          || visible in terminal ||   visible in file   || existing
  Syntax  ||  StdOut  |  StdErr  ||  StdOut  |  StdErr  ||   file   
==========++==========+==========++==========+==========++===========
    >     ||    no    |   yes    ||   yes    |    no    || overwrite
    >>    ||    no    |   yes    ||   yes    |    no    ||  append
==========++==========+==========++==========+==========++===========
   2>     ||   yes    |    no    ||    no    |   yes    || overwrite
   2>>    ||   yes    |    no    ||    no    |   yes    ||  append
==========++==========+==========++==========+==========++===========
   &>     ||    no    |    no    ||   yes    |   yes    || overwrite
   &>>    ||    no    |    no    ||   yes    |   yes    ||  append
==========++==========+==========++==========+==========++===========
 | tee    ||   yes    |   yes    ||   yes    |    no    || overwrite
 | tee -a ||   yes    |   yes    ||   yes    |    no    ||  append
==========++==========+==========++==========+==========++===========
 n.e. (*) ||   yes    |   yes    ||    no    |   yes    || overwrite
 n.e. (*) ||   yes    |   yes    ||    no    |   yes    ||  append
==========++==========+==========++==========+==========++===========
|& tee    ||   yes    |   yes    ||   yes    |   yes    || overwrite
|& tee -a ||   yes    |   yes    ||   yes    |   yes    ||  append

Script Identity

show_parms.sh

#!/bin/bash
echo
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ---------------------->  $1       "
echo "# \$2 ---------------------->  $2       "
echo "# path to me --------------->  ${0}     "
echo "# parent path -------------->  ${0%/*}  "
echo "# my name ------------------>  ${0##*/} "
echo
exit

Execution Notice on the next line, the first argument is called within double, and single quotes, since it contains two words.

$  /misc/shell_scripts/check_root/show_parms.sh "'hello there'" "'william'"

Output:

# arguments called with --->  'hello there' 'william'
# $1 ---------------------->  'hello there'
# $2 ---------------------->  'william'
# path to me -------------->  /misc/shell_scripts/check_root/show_parms.sh
# parent path ------------->  /misc/shell_scripts/check_root
# my name ----------------->  show_parms.sh

Help Menu

show_help() {
cat << EOF

This script does something.

Use: ${0##*/} -e {-r}
    -e   ENV            The environment in which to deploy.
                          Options: dev, qa, uat, prod
    -v   VPC            The VPC in which to deploy.
                          Options: foo, bar
    -h   HELP           Show this help menu.

Requirements:
    Programs required to be in your \$PATH:
      - bash (no Mac OSX FreeBSD sillyness)
      - jq
      - awscli
        - AWS Access ID and Secret Access Keys for each env
        - awscli profiles setup for each env

Examples:
    Launch the qa stack in us-east-2
      ./launch-stack.sh -e qa -n best-app

EOF
exit 1
}

Accepting Arguments

OPTIND=1
while getopts "he:v:n:" opt; do
  case "$opt" in
    h)
      show_help
      ;;
    e)
      arg_e='set'
      arg_e_val="$OPTARG"
      ;;
    :)
      echo "ERROR: Option -$OPTARG requires an argument."
      show_help
      ;;
    *)
      echo "ERROR: Unknown option!"
      show_help
      ;;
  esac
done
shift "$((OPTIND-1))"
[ "$1" = "--" ] && shift

Argument Sanities

Check for arguments

if [[ $# -eq 0 ]]; then
    echo "No args supplied!"
    show_help
fi

Accept only arguments passed with -

if [[ ! $1 =~ "^-" ]]; then
    echo "Must supply a supported argument!"
    show_help
fi

Ensure script is run only from a specified directory

if [[ ! ${PWD##*/} == "foo" ]]; then
    echo "This utility must be run from the 'foo' directory."
    exit 1
fi

Prevent execution in non-interactive environment

[[ $- == *i* ]] || return

Check if argument is valid

if [[ ! "$arg_m_val" =~ ^vite$|^webpack$ ]]; then 
  echo boo
fi

Log Output

function log() {
  # Usage: log <level> <output> <message>$
  case ${@:1} in
    0|emerg)
      level='\e[01;30;41mEMERGENCY\e[0m'
      ;;
    1|alert)
      level='\e[01;31;43mALERT\e[0m'
      ;;
    2|crit)
      level='\e[01;97;41mCRITICAL\e[0m'
      ;;
    3|err)
      level='\e[01;31mERROR\e[0m'
      ;;
    4|warn)
      level='\e[01;33mWARNING\e[0m'
      ;;
    5|notice)
      level='\e[01;30;107mNOTICE\e[0m'
      ;;
    6|info)
      level='\e[01;39mINFO\e[0m'
      ;;
    7|debug)
      level='\e[01;97;46mDEBUG\e[0m'
      ;;
    77|succ)
      level='\e[01;32mSUCCESS\e[0m'
      # Not a real severity level under RFC5425. Purely for display purposes.
      ;;
    *)
      echo -e "\e[01;31mERROR\e[00m: Invalid level argument!"
      exit 1
      ;;
  esac
  output=${@:2} # log | tty | both$
  msg=${@:3}
  [[ $output == "tty" ]] && echo -e "$($ts) - $level: $msg"
  [[ $output == "log" ]] && echo -e "$($ts) - $level: $msg" >> ~/${0##*/}.log
  [[ $output == "both" ]] && echo -e "$($ts) - $level: $msg" | tee -a ~/${0##*/}.log
}

Prompting for User Input

The function

function ask {
    while true; do
        if [ "${2:-}" = "Y" ]; then
            prompt="Y/n"
            default=Y
        elif [ "${2:-}" = "N" ]; then
            prompt="y/N"
            default=N
        elif [ "${2:-}" = "Range" ]; then
            prompt="${3:-}"
            default=0
        else
            prompt="y/n"
            default=
        fi
        read -p $"$1 [$prompt]: " reply
        if [ -z "$reply" ]; then
            reply=$default
        fi
        case "$reply" in
            Y*|y*|[1-99]) return 0 ;;
            N*|n*|0*) return 1 ;;
        esac
    done
}

if ask "$(echo -e 'whatsup?'\\\n'1) woot'\\\n'2) rawr'\\\n'3) grrr'\\\n'0) quit'\\\n\\\n'Enter Response')" Range 0-3; then
    answer="$reply"
else
    answer="no"
fi
echo $answer

if ask "Confirm: Stuff?" N; then
    answer="yes"
else
    answer="no"
fi
echo $answer

Multiple-choice prompts

if ask "$(echo -e 'whatsup?'\\\n'1) woot'\\\n'2) rawr'\\\n'3) grrr'\\\n'0) quit'\\\n\\\n'Enter Response')" Range 0-3; then
    answer="$reply"
else
    answer="no"
fi
echo $answer

Yes/No Answer

if ask "Confirm: Stuff?" N; then
    answer="yes"
else
    answer="no"
fi
echo $answer

Super Basic Unit Test

function rc {
  if [[ $? -eq $1 ]] ; then
    echo -e "$(date --utc +"%FT%T.%3NZ")" - "SUCCESS: $task" | tee -a "$logFile"
  else
    echo -e "$(date --utc +"%FT%T.%3NZ")" - "ERROR: $task" | tee -a "$logFile"
  fi
}

function et {
  echo -e "\n${task}..."
}

SANITIES

Ensure script doesn't execute twice

lock="/var/run/${0##*/}.lock"
exec 1000>$lock
if flock -n 1000; then
  echo -e "${0##*/} is already running! Exiting."
  exit 1
fi

Linux CLI Essentials

package management

general

List All Repositories

dnf repolist all

Search for a package

dnf search [strings]

Install a package

rpm -i <package>
dnf -i <package>

Check for updates

dnf check-update

Upgrade a package

rpm -U <package>
dnf update <package>

Reinstall a package and its dependencies

dnf reinstall <package>

Download a package to a specified destination

dnf install <package> --downloadonly --downloaddir=<dir>

Uninstall a package

rpm -e <package>
dnf remove <package>

List installed

rpm -qa
dnf list-installed

Display info on installed package

rpm -qi <package>
dnf info <package>

Display configuration files for a package

rpm -qc <package>

Display recently installed packages

rpm -qa --last

Check dependencies

rpm -qpR <package.rpm>
rpm -qR <package>

snap

Install snapd

dnf install snapd
ln -s /var/lib/snapd/snap /snap
ln -l /snap
systemctl enable --now snapd.socket

Search

snap search <string>

Install a package

snap install <package>

Fix Missing Shortcut

mkdir -p ~/.local/share/applications
ln -s /var/lib/snapd/desktop/applications/<package>.desktop ~/.local/share/applications/

List Installed

snap list

Get info on package

snap info --versbose vlc

Get logs for package

snap logs <package>

Get configuration for package

snap get <package>
snap get <package>.<configuration>

piping

pipe output to null

echo foo > /dev/null 2>&1

grep

spaces of various types and sizes in only tf files:

grep -riq --include \*.tf '^[[:blank:]]\+backend "*"' 

multiple strings:

grep 'foo\|bar' file.txt

strace /w redirect to stdout:

sudo strace -p $(pgrep apache2) 2>&1 | grep foo

Find email addresses in a file:

grep -E -o "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" filename.txt

There is no AND, so regex works:

grep 'Manager.*Sales' employee.txt

AND & OR:

grep 'Manager.*Sales\|Developer*Tech' employee.txt

Exclude a matching string:

grep -v string file.txt

Ignore case sensitivity:

grep -i string file.txt

Show only the matched string, not the entire line in which it is present within:

grep -o "Meow" file.txt

Print the file containing the query including those within subdirs:

grep -r ^David ~/some_dir/*

Same as above, but recursively, and ignoring case:

grep -rli ^David ~/some_dir/

Count the number of matches:

grep -c "stuff" file.txt

Show the line numbers of the matches:

grep -n "go" file.txt

Search only for the full word:

grep -w "of" file.txt

Print 3 lines after the match (-B for before the match & -C for before and after)

grep -A 3 "of" file.txt

sed

Insert line at top of file using 1i (the number one + i)

sed -i '1iStringToInsert' somefile.txt

removes the last . (skipps the first?)

ls -lhtr /data/ | grep -v '.ns' | sed 's/\(.*\)\./\1 /' | awk '!seen[$9]++'

awk

numfmt

numfmt --to=iec-i --suffix=B --padding=7 1 177152 48832200 1975684956

numfmt with awk

awk '
    function human(x) {
        if (x<1000) {return x} else {x/=1024}
        s="kMGTEPZY";
        while (x>=1000 && length(s)>1)
            {x/=1024; s=substr(s,2)}
        return int(x+0.5) substr(s,1,1)
    }
    {sub(/^[0-9]+/, human($1)); print}'

curl

Find the city where your traffic egresses

curl -s https://ipvigilante.com/$(curl -s icanhazip.com) | jq -r .data.city_name

Capture both the RESPONSE and the http_code

result=$(curl -X POST https://foo.bar/ -w ", %{http_code}")

find

Find files over 1GB

sudo find / -type f -size +1000000k -exec ls -lh {} \;

du

Super ls - Shows direcotry sizes

du -sh * | sort -n

Git

Show Commit Tree

alias git-commit-tree='git log --graph --pretty=oneline --abbrev-commit'

Commit tree grep

alias git-commit-grep='git log --oneline | grep $1'

Side-by-side git diff in the CLI.

function git-diff() { git difftool -y -x sdiff HEAD^ $1 |
pygmentize |
less -R }

Regex

Networking & Communications

Short Name

^(?!-)[A-Za-z0-9]{1,63}(?<!-)$

FQDN

Notes:

  • Allows for 63 character TLDs due to new TLDs being released & in consideration of RFC-1034
  • Allows for subdomained ccTLDs, such as co.uk, co.th, etc.
(([-0-9a-zA-Z]+)\.)+(([a-zA-Z]{2,63})(\.([a-zA-Z]{2}))?)

CIDR

(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\.d{1,3})/(\\d{1,2})

IPv4

/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

IPv6

/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/

URL

/^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/

E-Mail

'\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b'

RFC 5322

[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*

Location

ZIP/Postal Codes

/(^\d{5}(-\d{4})?$)|(^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$)/

Apps

IRSSI

List Networks /network list

Add Network /network add foo

Connect to a server & join a channel /connect liberachat /join #irssi

Switch between channels/windows alt + <channel number

Ignore joins/quits/nick changes on a specific channel /ignore -channels #foo,#bar * JOINS PARTS QUITS NICKS

Auto-connect to a server on startup /server add -auto -network IRCnet irc.freenode.net 6667 /server add -auto -net LiberaChat -tls -tls_verify irc.libera.chat 6697

Auto-join channels /channel add -auto #foo IRCnet

Keep logging of all conversations /set autolog on

Configurations /set eg /set nick foonick

Auto-ident with nickserv /network add -autosendcmd "/msg nickserv identify <password>; wait 2000" IRCnet

Save configuration /save

Hilight lines containing your nick /hilight <foo>

Enable nick higlight matches everywhere /set hilight_nick_matches_everywhere ON

Beep on private messages or highlights /set beep_msg_lvel MSGS HILIGHT DCCMSGS

Get Help /help [network|server|channel]

Window controls /WINDOW NEW - Create new split window /WINDOW NEW HIDE - Create new hidden window /WINDOW CLOSE - Close split or hidden window /WINDOW HIDE [<number>|<name>] - Make the split window hidden window /WINDOW SHOW <number>|<name> - Make the hidden window a split window /WINDOW SHRINK [<lines>] - Shrink the split window /WINDOW GROW [<lines>] - Grow the split window /WINDOW BALANCE - Balance the sizes of all split windows

References startup

Linux

Plasma

Move window Super + Left Click

Resize Window Super + Right Click

Zoom In/Out Super + +/-

AWS

ECR

Login

aws ecr --region <region> get-login-password | docker login --username AWS --password-stdin <accountId>.dkr.ecr.<region>.amazonaws.com

References

Markdown Cheatsheet

Markdown Cheatsheet

RFC3339Micro References

Syslog Redirector PR-6 Sentry TS Handling Splunk Timestamp Recognition Loggly Parsing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment