Bash

    Hello Summary

    # variable default value if unset
    v=${1:-world}
    echo "hello ${v}" # hello world (if no args)
    
    # arrays
    l=("hello")
    l+=("world")
    echo "${#l[@]}" # 2
    echo "${l[*]}" # hello world
    
    # conditions
    if [ 5 -ge 0 ] && [ 10 -ge 0 ]; then # can also be written [[ ... && ...]]
      echo "both positives" # both positive
    fi
    
    # 'function' and 'tricky::' are optional
    function tricky::variable() {
      a=5
      local b=10
    }
    
    echo "a=${a}, b=${b}" # a=,b=
    tricky::variable # call function
    echo "a=${a}, b=${b}" # a=5,b=
    
    # function (can be used as a command)
    run_ls() {
      local directory="$1"
      ls ${directory}
    }
    
    # redirect the standard and error output
    run_ls "/tmp" >/dev/null 2>&1 && echo "success" || echo "failed" # success
    
    run_ls "/nonexistingdir/lala" >/dev/null 2>&1 \
    && echo "success" \
    || echo "failed" # failed
    
    # in case you want to stop the script, you can add (set -e) and do something like
    # ... || (echo "failed" && exit 1)
    
    # loops
    for i in $(seq 1 5); do echo -n "${i}, "; done # 1, 2, 3, 4, 5,
    while true; do echo "test"; sleep 1s; break; done # test
    
    # case
    case ${option} in
      -l|--list)
        ls
      ;;
      *)
        echo "default" # default
      ;;
    esac
    

    Completion

    Here's an intersting example with the command ''pass''

    # completion file for bash
    
    # Copyright (C) 2012 Jason A. Donenfeld `<Jason@zx2c4.com>` and
    # Brian Mattern `<rephorm@rephorm.com>`. All Rights Reserved.
    # This file is licensed under the GPLv2+. Please see COPYING for more information.
    
    _pass_complete_entries () {
    	prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}"
    	suffix=".gpg"
    	autoexpand=${1:-0}
    
    	local IFS=$'\n'
    	local items=($(compgen -f $prefix$cur))
    	for item in ${items[@]}; do
    		if [[ $item == $prefix.* ]]; then
    			continue
    		fi
    
    		# if there is a unique match, and it is a directory with one entry
    		# autocomplete the subentry as well (recursively)
    		if [[ ${#items[@]} -eq 1 && $autoexpand -eq 1 ]]; then
    			while [[ -d $item ]]; do
    				local subitems=($(compgen -f "$item/"))
    				if [[ ${#subitems[@]} -eq 1 ]]; then
    					item="${subitems[0]}"
    				else
    					break
    				fi
    			done
    		fi
    
    		# append / to directories
    		[[ -d $item ]] && item="$item/"
    
    		item="${item%$suffix}"
    		COMPREPLY+=("${item#$prefix}")
    	done
    }
    
    _pass_complete_keys () {
    	local IFS=$'\n'
    	local GPG=gpg2
    	which $GPG >/dev/null || GPG=gpg
    	# Extract names and email addresses from gpg --list-keys
    	local keys="$($GPG --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d')"
    	COMPREPLY+=($(compgen -W "${keys}" -- ${cur}))
    }
    
    _pass()
    {
    	COMPREPLY=()
    	local cur="${COMP_WORDS[COMP_CWORD]}"
    	local commands="init ls show insert generate edit rm git help version"
    	if [[ $COMP_CWORD -gt 1 ]]; then
    		case "${COMP_WORDS[1]}" in
    			init)
    				COMPREPLY+=($(compgen -W "-e --reencrypt" -- ${cur}))
    				_pass_complete_keys
    				;;
    			ls|list|edit)
    				_pass_complete_entries
    				;;
    			show|-*)
    				COMPREPLY+=($(compgen -W "-c --clip" -- ${cur}))
    				_pass_complete_entries 1
    				;;
    			insert)
    				COMPREPLY+=($(compgen -W "-e --echo -m --multiline -f --force" -- ${cur}))
    				_pass_complete_entries
    				;;
    			generate)
    				COMPREPLY+=($(compgen -W "-n --no-symbols -c --clip -f --force" -- ${cur}))
    				_pass_complete_entries
    				;;
    			rm|remove|delete)
    				COMPREPLY+=($(compgen -W "-r --recursive -f --force" -- ${cur}))
    				_pass_complete_entries
    				;;
    			git)
    				COMPREPLY+=($(compgen -W "init push pull config log reflog" -- ${cur}))
    				;;
    		esac
    	else
    		COMPREPLY+=($(compgen -W "${commands}" -- ${cur}))
    		_pass_complete_entries 1
    	fi
    }
    
    complete -o filenames -o nospace -F _pass pass
    

    Environment

    To retrieve environment variable: env{bash}

    Note: Could also use set but it return the register functions too.

    Constant

    readonly var=value

    Arithmetic

    n1=1
    n2=1
    
    # $(( expression ))
    
    a=$(( n1+n2 )) # 2
    b=$(( n1/n2 )) # 1
    c=$(( n1-n2 )) # 0
    

    See more on official doc

    Shell Parameter Expansion

    Official source

    Example :

    bash --version # GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
    
    test="n=5=6=7"
    echo ${test} # n=5=6=7
    
    echo ${test#*=} # 5=6=7
    echo ${test#*=*=} # 6=7
    echo ${test##*=} # 7
    
    echo ${test%=*} # n=5=6
    echo ${test%=*=*} # n=5
    echo ${test%%=*} # n
    

    Bash Regex

    Example with host variable which start by "user." and continue by whatever or start by host1.

    if [[ "$HOST" =~ ^user.*|^host1 ]]; then
      echo "yes"
    fi
    

    FAQ / Tips

    Debug bash script

    bash -x script

    Note: You could also add ''-v'' option

    Or directly in script :

    #!/bin/bash
    
    ### Turn on debug mode ###
    set -x
    
    # Run shell commands
    
    echo "Hello $(LOGNAME)"
    echo "Today is $(date)"
    echo "Users currently on the machine, and their processes:"
    w
    
    ### Turn OFF debug mode ###
    set +x
    

    Note: set permit also to change option of shell (see more).

    Breakpoint

    bash -c "$SHELL"
    

    source

    Slugify

    echo $str | iconv -t ascii//TRANSLIT | sed -r s/[~\^]+//g | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z
    

    source

    Use bash completion from another command

    function _mycmd(){
      local current choice
      current=${COMP_WORDS[COMP_CWORD]}
    
      case "$COMP_CWORD" in
      1)
        choice="opt1 opt2"
        COMPREPLY=( $( compgen -W '$choice' -- $current ) )
      ;;
      2)
        COMPREPLY=( $(compgen -W 'the_other_command' -- $current) )
      ;;
      *)
        # idea based on sudo bash completion
        local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
        _command_offset 2
        return
      ;;
      esac
    }
    
    complete -F _mycmd mycmd
    

    Note/Todo: the command will look like mycmd opt1 the_other_command .... I did not find a way to get rid of the_other_command to make it works

    Inspired from:

    lock a file (multiple access)

    # lock
    exec 3>filename # open a file handle; this part will always succeed
    flock -x 3      # lock the file handle; this part will block
    
    # release
    exec 3>&-       # close the file handle
    

    equivalent code in a block

    {
      flock -x 3
      ...other stuff here...
    } 3>filename
    

    with new bash version, no need to fd number:

    # this requires a very new bash -- 4.2 or so.
    exec {lock_fd}>filename  # open filename, store FD number in lock_fd
    flock -x "$lock_fd"      # pass that FD number to flock
    exec {lock_fd}>&-         # later: release the lock
    

    source