Differences between revisions 10 and 12 (spanning 2 versions)
Revision 10 as of 2021-04-10 20:03:53
Size: 3141
Editor: SamatJain
Comment:
Revision 12 as of 2021-04-25 02:46:19
Size: 6570
Editor: SamatJain
Comment: ANSI-C and Unicode escaping
Deletions are marked like this. Additions are marked like this.
Line 79: Line 79:
== 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]].

Interesting bash aliases and functions:

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':

   1 % cat foo
   2 FOO=''
   3 [ -z "${FOO:-}" ] && echo 1
   4 [ -z "${BAR:-}" ] && echo 2
   5 [ -v FOO ] && echo 3
   6 [ -v BAR ] && echo 4
   7 % bash -u ./foo
   8 1
   9 2
  10 3

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

  • $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.

"Strict Mode"

Tools

Use shellcheck with timonwong.shellcheck plugin.

Use bash-language-server.

Gotchas

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

   1 # Define
   2 arr=("one" "two")
   3 declare -a arr=("one" "two")
   4 
   5 # Append
   6 arr+=("three")
   7 
   8 # Merge all items, space delimited
   9 echo "${arr[@]}"
  10 # one two three
  11 
  12 # Join by delimiter
  13 echo $(IFS=, ; echo "${arr[*]}")
  14 # one,two,three
  15 
  16 # Indexes of the array (i.e. Python's enumerate)
  17 echo "${!arr[@]}"
  18 # 0 1 2
  19 
  20 # Array length
  21 echo "${#arr[@]}"
  22 # 3
  23 
  24 # Remove an element
  25 unset arr[3]
  26 
  27 # Display item by position
  28 echo "${arr[1]}"
  29 # two
  30 
  31 # Loop over each individual items
  32 # If inside a quoted string
  33 # '@' returns each individual item
  34 for i in "${arr[@]}"; do
  35   echo "$i"
  36 done
  37 # one
  38 # two
  39 # three
  40 
  41 # If inside a quoted string
  42 # '*' will merge together by IFS
  43 for i in "${arr[*]}"; do
  44   echo "$i"
  45 done
  46 # one two three
  47 
  48 # Copy an array
  49 declare -a arr2=("${arr[@]}")
  50 
  51 # Combine two arrays
  52 declare -a arr3=("${arr1[@]}" "${arr2[@]}")
  53 
  54 # Randomly shuffle an array
  55 shuf -e "${arr[@]}"
  56 shuffled=(shuf -e "${arr[@]}")
  57 
  58 # Delete an entire array
  59 unset arr arr1 arr2 arr3
  60 
  61 # Subset of an array
  62 # ${arr[@]:$start} # from start to end of array
  63 # ${arr[@]::$count} # first count-many elements from beginning
  64 # ${arr[@]:$start,$count} # count-many elements from start
  65 echo "${arr[@]:1:1}"
  66 
  67 # Check if array is empty
  68 if [[ ${#arr[@]} -eq 0 ]]; then ... fi
  69 
  70 # Check if array is not empty
  71 if [[ ${#arr[@]} -gt 0 ]]; then ... fi
  72 
  73 # Check item "one" is in array
  74 [[ ${arr[*]} =~ ^|[[:space:]])"one"($|[[:space:]]) ]] && echo "exists" || echo "doesn't exist"
  75 # exists
  76 
  77 # Check if partial match is in array
  78 [[ ${arr[*]} =~ 'on' ]] && echo "exists" || echo "doesn't exist"
  79 # exists
  80 
  81 # Read into an array from a file, safely. Preserves spaces, special characters, etc.
  82 # bash 4.0
  83 mapfile -t inputarr < file.txt
  84 
  85 # Read into an array from a command, safely. Preserve spaces, special characters, etc.
  86 # -t removes trailing spaces
  87 readarray -t inputarr < <(seq 5)
  88 declare -p inputarr
  89 # declare -a inputarr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")
  90 

Associative arrays/hash tables

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.

# ANSI escape
VAR=$'\xe2\x98\xa2'
# Unicode escape
VAR=$'\u2622'

See also: ANSI-C quoting from the Bash Reference Manual.

Never Remember

Process Substition is the name for <(command) syntax.

Redirect stderr to stdout with 2>&1, e.g.:

Some-Command 2>&1 > log.txt

SamatsWiki: Bash (last edited 2021-04-25 02:46:19 by SamatJain)