Files
oam/knowledge base/bash.md
2023-03-16 00:46:54 +01:00

8.3 KiB

Bourne Again SHell

  1. TL;DR
  2. Startup files loading order
  3. Functions
  4. Substitutions
    1. !! (command substitution)
    2. ^^ (caret substitution)
  5. Here documents
  6. Keys combinations
  7. Check if a script is sourced by another
  8. Gotchas
    1. Exist statuses of killed commands
    2. Go incognito
  9. Further readings
  10. Sources

TL;DR

# Declare arrays.
ARRAY=(
  "first_element"
  "second_element" "nth_element"
)

# Get the length of arrays.
# A.K.A. number of elements.
ARRAY_LEN=${#ARRAY[@]}

# Access all elements in arrays with referencing.
echo ${ARRAY[@]}
echo ${ARRAY[*]}

# Access the last value of arrays.
echo ${ARRAY[-1]}
echo ${ARRAY: -1}

# Get a slice of 4 elements from an array.
# Start from the element with index number 2.
echo ${ARRAY:2:4}

# Declare functions.
functionName () {}
function functionName {}

# Declare functions on a single line.
functionName () { command1 ;; command N ; }

# Get all the arguments in input.
echo $@

# Of all the arguments in input, return only those which are existing directories.
DIRECTORIES=()
for (( I = $# ; I >= 0 ; I-- )); do
  if [[ -d ${@[$I]} ]]; then
    DIRECTORIES+=${@[$I]}
  else
    local COMMAND="${@:1: 1-$I}"
    break
  fi
done

# Print all shell and environment variables.
( set -o posix ; set )

# Print exported variables only.
export -p

# Run a command or function on exit, kill or error.
trap "rm -f $tempfile" EXIT SIGTERM ERR
trap function-name EXIT SIGTERM ERR

# Disable CTRL-C.
trap "" SIGINT

# Re-enable CTRL-C.
trap - SIGINT

# Bash 3 and `sh` have no built-in means to convert case of a string, but the
# `awk`, `sed` or `tr` tools can be used instead.
echo $(echo "$name" |  tr '[:upper:]' '[:lower:]' )
echo $(tr '[:upper:]' '[:lower:]' <<< "$name")

# Bash 5 has a special parameter expansion for upper- and lowercasing strings.
echo ${name,,}
echo ${name^^}

# Add a clock to the top-right part of the terminal.
while sleep 1
do
  tput sc;
  tput cup 0 $(($(tput cols)-29))
  date
  tput rc
done &

# Show a binary clock.
watch -n 1 'echo "obase=2; `date +%s`" | bc'

# Fork bomb.
:(){ :|: & };:

Startup files loading order

On startup:

  1. (if login shell) /etc/profile
  2. (if interactive and non login shell) /etc/bashrc
  3. (if login shell) ~/.bash_profile
  4. (if login shell and ~/.bash_profile not found) ~/.bash_login
  5. (if login shell and no ~/.bash_profile nor ~/.bash_login found) ~/.profile
  6. (if interactive and non login shell) ~/.bashrc

Upon exit:

  1. (if login shell) ~/.bash_logout
  2. (if login shell) /etc/bash_logout

Functions

A function automatically returns the exit code of the last command in it.

Substitutions

!! (command substitution)

Substitutes !! with the last command in your history

$ echo 'hallo!'
hallo!

$ !!
echo 'hallo!'
hallo!

$ sudo !!
sudo echo 'hallo!'
[sudo] password for user:
hallo!

^^ (caret substitution)

Re-runs a command replacing a string.

$ sudo apt search tmux
…

$ ^search^show
sudo apt show tmux
…

Here documents

A Here document (heredoc) is a type of redirection that allows you to pass multiple lines of input to a command.

[COMMAND] <<[-] 'DELIMITER'
  HERE-DOCUMENT
DELIMITER
  • the first line must start with an optional command followed by the special redirection operator << and the delimiting identifier
  • one can use any string as a delimiting identifier, the most commonly used being EOF or END
  • if the delimiting identifier is unquoted, the shell will substitute all variables, commands and special characters before passing the here-document lines to the command
  • appending a minus sign to the redirection operator (<<-), will cause all leading tab characters to be ignored
    this allows one to use indentation when writing here-documents in shell scripts
    leading whitespace characters are not allowed, only tabs are
  • the here-document block can contain strings, variables, commands and any other type of input
  • the last line must end with the delimiting identifier
    white space in front of the delimiter is not allowed
$ cat << EOF
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF
The current working directory is: /home/user
You are logged in as: user
$ cat <<-'EOF' | sed 's/l/e/g' > file.txt
  Hello
  World
EOF
$ cat file.txt
Heeeo
Wored

Keys combinations

  • Ctrl+L: clear the screen (instead of typing clear)
  • Ctrl+R: reverse search your Bash history for a command that you have already run and wish to run again

Check if a script is sourced by another

(return 0 2>/dev/null) \
&& echo "this script is not sourced" \
|| echo "this script is sourced"

Gotchas

Exist statuses of killed commands

The exit status of a killed command is 128 + n if the command was killed by signal n:

$ pgrep tryme.sh
880
$ kill -9 880
$ echo $?
137

Go incognito

See How do I open an incognito bash session on unix.stackexchange.com

HISTFILE=

You can also avoid recording a single command simply preceding it with space

echo $RECORDED
 echo $NOT_RECORDED

Further readings

Sources