${str:position} # substring starting at position ${str:position:len} # substring starting at position with length len ${str#ubstring} # delete shortest match from front ${str##substring} # delete longest match from front ${str%substring} # delete shortest match from back ${str%%substring} # delete longest match from back ${str/pattern/replacement} # pattern replace ${str/#pattern/replacement} # pattern replace at front ${str/%pattern/replacement} # pattern replace at end ${str//pattern/replacement} # global pattern replace
${str-default} # set 'default' if not set ${str:-default} # set 'default' if not set (even if declared null) ${str=default} # set 'default' if not set ${str:=default} # set 'default' if not set (even if declared null) ${str+value} # set 'value' if $str is set, otherwise set null ${str:+value} # set 'value' if $str is set (even if declared null), otherwise set null ${str?error} # abort with 'error' if not set ${str:?error} # abort with 'error' if not set (and not null)
Indexed arrays require no declaration
arr=("string 1", "string 2", "string 3") arr=([1]="string 1", [2]="string 2", [3]="string 3") arr[4]="string 4"
Check below under “Hashes” for accessing the different properties of an array.
Since Bash v4
# Hashes need declaration! declare -A arr # Assigning values to associative arrays arr[my key]="my value" arr["my key"]="my value" arr[$my_key]="my value" # Fetching values echo ${arr[my key]} echo ${arr["my key"]} echo ${arr[$my_key]} # Accessing the array ${arr[@]} # Returns all indizes and their items (doesn't work with associative arrays) ${arr[*]} # Returns all items ${!arr[*]} # Returns all indizes ${#arr[*]} # Number elements ${#arr[$n]} # Length of $nth item # Pushing to array arr+=("new string value", "another new value")
Bash allows here documents like this
cat <<EOT [...] EOT
To disable substitution in the here doc text quote the marker with single or double quotes.
cat <<'EOT'
To strip leading tabs use
cat <<-EOT
For simple tracing add a
set -x
in the script or append the “-x” to the shebang or run the script like this:
bash -x <script name>
As “set -x” enables tracing you can disable it with “set +x” again. This allows tracing only a part of the code (e.g. a condition in an inner loop). Additionally to “-x” you may want to set “-v” to see the shell commands that are executed. Combine both to
set -xv
It is a good practice to use
set -euo pipefail
which ensures
# Establish a connection to 91.92.93.94:80 on file handle 4 with if ! exec 4<> /dev/tcp/91.92.93.94/80; then echo "ERROR: Connection failed!" fi # Write something echo -e "GET / HTTP/1.0\n" >&4 # Read something cat <&4 # Close the socket exec <&4- exec >&4-
The complete list of bash 4.2 test operators:
-a FILE True if file exists. -b FILE True if file is block special. -c FILE True if file is character special. -d FILE True if file is a directory. -e FILE True if file exists. -f FILE True if file exists and is a regular file. -g FILE True if file is set-group-id. -h FILE True if file is a symbolic link. -L FILE True if file is a symbolic link. -k FILE True if file has its sticky bit set. -p FILE True if file is a named pipe. -r FILE True if file is readable by you. -s FILE True if file exists and is not empty. -S FILE True if file is a socket. -t FD True if FD is opened on a terminal. -u FILE True if the file is set-user-id. -w FILE True if the file is writable by you. -x FILE True if the file is executable by you. -O FILE True if the file is effectively owned by you. -G FILE True if the file is effectively owned by your group. -N FILE True if the file has been modified since it was last read. FILE1 -nt FILE2 True if file1 is newer than file2 (according to modification date). FILE1 -ot FILE2 True if file1 is older than file2. FILE1 -ef FILE2 True if file1 is a hard link to file2.
The complete list of bash 4.2 string operators:
-z STRING True if string is empty. -n STRING STRING True if string is not empty. STRING1 = STRING2 True if the strings are equal. STRING1 != STRING2 True if the strings are not equal. STRING1 < STRING2 True if STRING1 sorts before STRING2 lexicographically. STRING1 > STRING2 True if STRING1 sorts after STRING2 lexicographically.
Sometimes you might need to pass a file name when you want to pipe output from a commands.
Then you could write to a file first and then used it, but you can also use the “>()” or “\<()” operator.
This can be used with all tools that demand a file name parameter:
diff <(echo abc;echo def) <(echo abc;echo abc)
Here are some improvements for the bash history handling:
unset HISTFILE # Stop logging history in this bash instance HISTIGNORE="[ ]*" # Do not log commands with leading spaces HISTIGNORE="&" # Do not log a command multiple times # Change up/down arrow key behavior to navigate only similar commands bind '"\e[A":history-search-backward' bind '"\e[B":history-search-forward' bind '"\e[C":forward-char' bind '"\e[D":backward-char'
To add timestamps to your history set the following environment variable:
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S " # Log with timestamps
If you do not like Ctrl-R to navigate the history you can define other keys as PgUp and PgDown in /etc/inputrc:
"\e[5~": history-search-backward "\e[6~": history-search-forward
For a secure bash configuration add the following settings to your global/users bashrc
HISTIGNORE="" HISTCONTROL="" HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S ' HISTFILE=~/.bash_history HISTFILESIZE=2000 readonly HISTFILE readonly HISTSIZE readonly HISTFILESIZE readonly HISTIGNORE readonly HISTCONTROL readonly HISTTIMEFORMAT shopt -s histappend
and finally mark the history file append only:
chattr +a $HISTFILE
See: https://spin.atomicobject.com/2017/08/24/start-stop-bash-background-process/
trap "exit" INT TERM ERR trap "kill 0" EXIT background_something & wait
trap 'kill $(jobs -p)' EXIT
Setup your own bash completion schemas.
Here is a git example:
complete -W 'add branch checkout clone commit diff grep init log merge mv pull push rebase rm show status tag' git complete -p # To list defined completion schemes
NOTE: This example probably already comes prepared with your Linux distribution.
You might want to check default definitions installed in /etc/bash_completion.d for a good starting point.
trap true TERM kill -- -$$
Try to use the “-i” switch:
sudo -i -u <user>
NOTE: If it does not work, you might need to investigate and change the PAM configuration.
To avoid incorrect line break behaviour when editing the command line you need to escape control characters in PS1 like this:
\[color definition\]
For example:
\[\033[31m\] some text \[\033[0m\]