<> Interesting bash aliases and functions: * [[http://fvue.nl/wiki/Bash:_Cdots|Cdots]] * [[http://fvue.nl/wiki/Ssh_to_current_working_dir_on_server|SSH to CWD on a remote server]] * [[http://www.fvue.nl/wiki/Bash:_Change_directory_to_project:_cdp|cd to project directory]] * https://github.com/Bash-it/bash-it: Community bash "framework" * [[https://google.github.io/styleguide/shellguide.html|Google's shell script style guide]]. Also good is [[https://bash3boilerplate.sh/|Bash 3 Boilerplate]] == Neat features == === Edit a command in $EDITOR === Ctrl-x Ctrl-e will edit a command in $EDITOR before execution. With `set -o vi` in bash/readline, `v` in command mode will do the same. === -v for testing set variables, while handling undefined ones === -v: True if the shell variable varname is set (has been assigned a value). bash >=4.2 supports -v for testing for *set* variables while handling empty ones, also no specials needs when running under 'set -u': {{{#!highlight sh % cat foo FOO='' [ -z "${FOO:-}" ] && echo 1 [ -z "${BAR:-}" ] && echo 2 [ -v FOO ] && echo 3 [ -v BAR ] && echo 4 % bash -u ./foo 1 2 3 }}} [[https://mobile.twitter.com/mikagrml/status/1222225444558209024?s=19|source]] also: If you use bash, you should really use [[ ]] instead of [ ]. It can do everything [ can (and then some, like ERE and glob matches), but is a shell keyword, which improves ergonomics quite a bit. See [ $x = 0 ] vs. [[ $x = 0]] after `unset x`, for example. == Special Variables == {{{#!text_markdown * $0 - The filename of the current script. Do not use! * $n - The Nth argument passed to script was invoked or function was called. E.g. $1, etc. * $# - The number of argument passed to script or function. * $@ - All arguments passed to script or function. * $* - All arguments passed to script or function. * $? - The exit status of the last command executed. * $$ - The process ID of the current shell. For shell scripts, this is the process ID under which they are executing. * $! - The process number of the last background command. * $- - current options set for the shell * $_ - most recent parameter, or the absolute path of the command used to start the current shell See [Special Parameters from the Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html). }}} == "Strict Mode" == * [[http://redsymbol.net/articles/unofficial-bash-strict-mode/|Unofficial Bash Strict Mode]] == Tools == Use shellcheck with timonwong.shellcheck plugin. Use bash-language-server. == Gotchas == * [[https://thomask.sdf.org/blog/2019/11/09/take-care-editing-bash-scripts.html|Take care editing bash scripts]]: Bash processes scripts as they execute, so saving over a script that is running can have side effects. == Types and variables == Can use `declare` (conventional r/w variable), `local` (scoped to function only), and `readonly`, along with modifiers (e.g. `-a`), to declare variables. E.g. `readonly -a` declares a read-only array. === Arrays === {{{#!highlight sh # Define arr=("one" "two") declare -a arr=("one" "two") # Append arr+=("three") # Merge all items, space delimited echo "${arr[@]}" # one two three # Join by delimiter echo $(IFS=, ; echo "${arr[*]}") # one,two,three # Indexes of the array (i.e. Python's enumerate) echo "${!arr[@]}" # 0 1 2 # Array length echo "${#arr[@]}" # 3 # Remove an element unset arr[3] # Display item by position echo "${arr[1]}" # two # Loop over each individual items # If inside a quoted string # '@' returns each individual item for i in "${arr[@]}"; do echo "$i" done # one # two # three # If inside a quoted string # '*' will merge together by IFS for i in "${arr[*]}"; do echo "$i" done # one two three # Copy an array declare -a arr2=("${arr[@]}") # Combine two arrays declare -a arr3=("${arr1[@]}" "${arr2[@]}") # Randomly shuffle an array shuf -e "${arr[@]}" shuffled=(shuf -e "${arr[@]}") # Delete an entire array unset arr arr1 arr2 arr3 # Subset of an array # ${arr[@]:$start} # from start to end of array # ${arr[@]::$count} # first count-many elements from beginning # ${arr[@]:$start,$count} # count-many elements from start echo "${arr[@]:1:1}" # Check if array is empty if [[ ${#arr[@]} -eq 0 ]]; then ... fi # Check if array is not empty if [[ ${#arr[@]} -gt 0 ]]; then ... fi # Check item "one" is in array [[ ${arr[*]} =~ ^|[[:space:]])"one"($|[[:space:]]) ]] && echo "exists" || echo "doesn't exist" # exists # Check if partial match is in array [[ ${arr[*]} =~ 'on' ]] && echo "exists" || echo "doesn't exist" # exists # Read into an array from a file, safely. Preserves spaces, special characters, etc. # bash 4.0 mapfile -t inputarr < file.txt # Read into an array from a command, safely. Preserve spaces, special characters, etc. # -t removes trailing spaces readarray -t inputarr < <(seq 5) declare -p inputarr # declare -a inputarr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5") }}} * [[https://www.gnu.org/software/bash/manual/html_node/Arrays.html|Bash Reference Manual: Arrays]] === Associative arrays/hash tables === {{{#!highlight sh numbers=off declare -A ht ht["one"]=1 ht["two"]=2 # Print values, all one line echo "${ht[@]}" # 2 1 # Print keys, all one line echo "${!ht[@]}" # two one # Iterate over keys and values for k in "${!ht[@]}"; do echo "$k=${ht[$k]}" done # two=2 # one=1 # Hash length echo "${#ht[@]}" # Remove a key unset ht["one"] echo "${ht[@]}" # 2 # Check if key is in hash [[ -z "${ht["one"]}" ]] && echo "exists" || echo "doesn't exist" }}} == Escaping characters == tl;dr: bash (TODO: check which version) lets you just use the character via copy-and-paste. Make sure to be using a Unicode encoding, e.g. LANG="en_US.UTF-8". Use special `$"..." quoting to allow bash to read ANSI C and Unicode escapes. E.g. {{{#!highlight sh numbers=off # ANSI escape VAR=$'\xe2\x98\xa2' # Unicode escape VAR=$'\u2622' }}} See also: [[https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html|ANSI-C quoting from the Bash Reference Manual]]. == Never Remember == [[https://en.wikipedia.org/wiki/Process_substitution|Process Substition]] is the name for `<(command)` syntax. Redirect stderr to stdout with `2>&1`, e.g.: {{{#!highlight sh numbers=off Some-Command 2>&1 > log.txt }}}