BASH - romitagl/kgraph GitHub Wiki

BASH

Shebang

#!/bin/bash

When a text file with a shebang is used as if it is an executable in a Unix-like operating system, the program loader mechanism parses the rest of the file's initial line as an interpreter directive.

Examples

Some typical shebang lines:

  • #!/bin/sh – Execute the file using the Bourne shell, or a compatible shell, assumed to be in the /bin directory
  • #!/bin/bash – Execute the file using the Bash shell
  • #!/usr/bin/env python3 – Execute with a Python interpreter, using the env program search path to find it
  • #!/bin/false – Do nothing, but return a non-zero exit status, indicating failure. Used to prevent stand-alone execution of a script file intended for execution in a specific context, such as by the . command from sh/bash, source from csh/tcsh, or as a .profile, .cshrc, or .login file.

Keyboard Shortcuts

  • CTRL-a Goes to the beginning of the line
  • CTRL-e Goes to the end of the line
  • CTRL-w Deletes the word before the cursor
  • CTRL-u Deletes from beginning of line to cursor position
  • CTRL-k Deletes all text from the cursor to the end of line

Parenthesis

Parenthesis ()

Double parentheses (( )) are used for arithmetic. Variables used inside double parentheses do not need to be prefixed with '$':

((var++))
((var = 3))
for ((i = 0; i < VAL; i++))
echo $((var + 2))

Brackets []

Square brackets [] are used for test construct:

VAR=2
if [ $VAR -eq 2 ] ; then echo 'yes'; fi
# yes

Double square brackets [[]] offer extended functionality to single square brackets, useful for the regular expression operator =~:

VAR='some string'
if [[ $VAR =~ [a-z] ]]; then echo 'is alphabetic'; fi
# is alphabetic

Braces {}

Curly braces {} are used to delimit a variable:

foo='stage'
echo $fooone
# ... returns empty line
echo ${foo}one
# stageone

Curly braces are also used for parameter expansion:

var="abcdefg"; echo ${var%d*}
# abc

Strings

  • to extract all characters in a string after a dot (.): ${string#*.}
  • get the length of a string: ${#string}
  • to replace characters (example a space ' ' with the url encoded version '%20') in the TEST variable: "${TEST// /%20}". More complete example: export TEST="a b c"; echo "${TEST// /%20}"
  • change the case of the string stored in the variable to lowercase: echo ${string,,}
  • String Conditions:
    • Equal: [[ STRING == STRING ]]
    • Not Equal: [[ STRING != STRING ]]
    • Empty string: [[ -z STRING ]]
    • Not empty string: [[ -n STRING ]]
    • Regular expression match: [[ STRING =~ STRING ]]

bash

File Conditions

Bash provides a set of file conditionals, that can be used with the if statement, including those in the table:

  • -e checks if the file exists.
  • -d checks if the file is a directory.
  • -f checks if the file is a regular file (i.e. not a symbolic link, device node, directory, etc.)
  • -s checks if the file is of non-zero size.
  • Is a file: [[-f FILE]]
  • Is a directory: [[ -d FILE ]]
  • Exists: [[ -e FILE ]]
  • Is readable, Writable, executable: [[ -r -w -x FILE ]]
  • Is symbolic link: [[ -h FILE ]]

Conditionals

if [[ $a -gt 4 ]]; then
  echo "$a is greater than 4"
elif [[ $a -lt 4 ]]; then
  echo "$a less than 4"
else
  echo "$a is equal 4"
fi

Numeric Conditions

  • Equal: [[ NUM -eq NUM ]]
  • Not equal: [[ NUM -ne NUM ]]
  • Less than: [[ NUM -lt NUM ]]
  • Less than or equal to: [[ NUM -le NUM a]]
  • Greater than ore qual to: [[NUM-gtNUM]] [[NUM-geNUM]]

Debugging

  • turn on shell debugging: set -x
  • turn off shell debugging: set +x

Change case

  • converts text from cursor to the end of the word to uppercase: Esc + u
  • converts text from cursor to the end of the word to lowercase: Esc + l
  • converts letter under the cursor to uppercase, rest of the word to lowercase: Esc + c

Variables

  • check if a variable is set: if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi. ${var+x} is a parameter expansion which evaluates to nothing if var is unset, and substitutes the string x otherwise.

substitution within quotes

foo=bar
echo $foo
# bar
echo "$foo"
# bar
# single quotes cause variables to not be expanded
echo '$foo'
# $foo
# single quotes within double quotes will not cancel expansion and will be part of the output
echo "'$foo'"
# 'bar'
# doubled single quotes act as double quotes making variables expand
echo ''$foo''
# bar

Scripts

Template

#!/usr/bin/env bash

# when a command fails, bash exits instead of continuing with the rest of the script
set -o errexit
# this will make the script fail, when accessing an unset variable
set -o nounset
# this will ensure that a pipeline command is treated as failed, even if one command in the pipeline fails
set -o pipefail
# enable debug mode, by running your script as TRACE=1 ./script.sh
if [[ "${TRACE-0}" == "1" ]]; then
    set -o xtrace
fi

if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then
    echo 'Usage: ./script.sh arg-one arg-two

This is an awesome bash script to make your life better.

'
    exit
fi

cd "$(dirname "$0")"

main() {
    echo do awesome stuff
}

main "$@"

Examples

  • make the parent process wait for its child:
sleep 30 &
wait $!
  • display animation until a specific time-consuming task completes:
#!/bin/bash
sleep 5 &
pid=$!
frames="/ | \\ -"
while kill -0 $pid 2&>1 > /dev/null;
do
    for frame in $frames;
    do
        printf "\r$frame Loading..." 
        sleep 0.5
    done
done
printf "\n"
  • multiline text file:
cat << EOF > file.txt
this is
a text
file
EOF
  • iterate all lines of a file:
while read p; do
  echo $p
done <file.txt
  • for loop: for i in {1..3}; do echo 'hello'; done

  • for loop with timeout: timeout 0.3s bash -c 'for i in {1..10}; do sleep 0.1; echo $i; done'

  • busy infinite loop: while :; do : ; done

  • parallel command executions:

#!/bin/bash
function task1() {
    echo "Running task1..."
    sleep 5
}
function task2() {
    echo "Running task2..."
    sleep 5
}
task1 &
task2 &
# keep the script instance active until background jobs complete their execution
wait
echo "All done!"
  • append column from file2 to file1:
#!/bin/bash

if [[ $# != 2 ]]; then echo "expected 2 input files"; exit 1; fi

printf "params: %s\n" $*

file1=$(sort $1)
# take only 2nd column
file2=$(sort $2 | awk '{ print $2}')

# check that files have the same line count
if [[ $(wc -l <(echo "$file1") ) !=  $(wc -l <(echo "$file2") ) ]]; then echo "files lines n. mismatch"; exit 1; fi

# concatenate file2 column to file1 columns
paste <(echo "$file1") <(echo "$file2")

# the three commands in the following example will all execute, even if the ones preceding them fail:
make ; make install ; make clean

# you may want to abort subsequent commands when an earlier one fails. You can do this using the && (and) operator as in:
make && make install && make clean

IF

# if and else loop for string matching
if [[ "$c" == "read" ]]; then outputdir="seq"; else outputdir="write" ; fi

# Test if myfile contains the string 'test':
if grep -q hello myfile; then echo -e "file contains the string!" ; fi

# Test if mydir is a directory, change to it and do other stuff:
if cd mydir; then
  echo 'some content' >myfile
else
  echo >&2 "Fatal error. This script requires mydir."
fi

# if variable is null
if [ ! -s "myvariable" ]; then echo -e "variable is null!" ; fi
#True of the length if "STRING" is zero.

# Using test command (same as []), to test if the length of variable is nonzero
test -n "$myvariable" && echo myvariable is "$myvariable" || echo myvariable is not set

# Test if file exist
if [ -e 'filename' ]
then
  echo -e "file exists!"
fi

# Test if file exist but also including symbolic links:
if [ -e myfile ] || [ -L myfile ]
then
  echo -e "file exists!"
fi

# Test if the value of x is greater or equal than 5
if [ "$x" -ge 5 ]; then echo -e "greater or equal than 5!" ; fi

# Test if the value of x is greater or equal than 5, in bash/ksh/zsh:
if ((x >= 5)); then echo -e "greater or equal than 5!" ; fi

# Use (( )) for arithmetic operation
if ((j==u+2)); then echo -e "j==u+2!!" ; fi

# Use [[ ]] for comparison
if [[ $age -gt 21 ]]; then echo -e "forever 21!!" ; fi

Terminal Output Text Styles

The tput Unix program offers commands to control the current terminal screen. It provides commands to change the terminal cursor position, retrieve terminal information, and change text styles.

Example that prints different text styles:

#!/bin/bash
bold=$(tput bold)
underline=$(tput smul)
italic=$(tput sitm)
info=$(tput setaf 2)
error=$(tput setaf 160)
warn=$(tput setaf 214)
reset=$(tput sgr0)
echo "${info}INFO${reset}: This is an ${bold}info${reset} message"
echo "${error}ERROR${reset}: This is an ${underline}error${reset} message"
echo "${warn}WARN${reset}: This is a ${italic}warning${reset} message"

Additional References:

⚠️ **GitHub.com Fallback** ⚠️