Laboratorium Komputerowe Progmar
Marcin Załęczny

We are using cookies in the page. If you use the page you agree for the cookies.      Close

Bash - programming

The command below executes specified subcommand command and loads its output into positional variables ($1, $2, ...). Every output's part is separated by a sign from $IFS variable: set -- $( command ) for example: set -- $( ls -l "file_name" ) returns: $1=-rwxr-xr-x, $2=1, $3=mzaleczny, $4=mzleczny, and so on.

Positional parameters can be deleted with command: set --

Saves specified function in the environment so the function is available for all child processes: export -f function_name

Displays all environment variables. In opposite to set command it doesn't display exported functions: printenv

Shifts all positional parameteres one step to the left. Parameter $1 gets removed, parameter $2 becomes parameter $1, parameter $3 becomes parameter $2, and so on: shift

Shifts all positional parameteres specified amount of steps to the left. First number of parameters get removed: shift number

Exits current script with return code equal to number: exit number

Tests if current working directory contains file or directory "name": test -a name

Tests if current working directory contains special block file "file_name": test -b file_name

Tests if current working directory contains special character file "file_name": test -c file_name

Tests if current working directory contains directory "directory_name": test -d directory_name

Tests if current working directory contains file or directory "name": test -e name

Tests if current working directory contains regular file "file_name": test -f file_name

Tests if current working directory contains file "file_name" and if it has set-group-id bit set: test -g file_name

Tests if current working directory contains symbolic link "name": test -h name or test -L name

Tests if current working directory contains file "file_name" and if it has sticky-bit set: test -k file_name

Tests if current working directory contains named stream (FIFO) "name": test -p name

Tests if current working directory contains file or directory "name" and if it is readable: test -r name

Tests if current working directory contains file "file_name" and if its size is greater than 0: test -s file_name

Tests if specified descriptor "descriptor_number" is opened and attached to a terminal (keyboard or screen): test -t descriptor_number

Tests if current working directory contains file "file_name" and if it has set-user-id bit set: test -u file_name

Tests if current working directory contains file or directory "name" and if it is writable: test -w name

Tests if current working directory contains file or directory "name" and if it is executable: test -x name

Tests if current working directory contains file or directory "name" and if its owner is effective group id: test -G name

Tests if current working directory contains file "file_name" and if it has changed since it's last read: test -N file_name

Tests if current working directory contains file or directory "name" and if its owner is effective user id: test -O name

Tests if two specified files are located in the same file system and if they are associated to the same i-node: test file_name1 -ef file_name2

Tests if file_name1 is newer (according to modification date) than file_name2 or if file_name1 exists and file_name2 does not: test file_name1 -nt file_name2

Tests if file_name1 is older (according to modification date) than file_name2 or if file_name2 exists and file_name1 does not: test file_name1 -ot file_name2

Tests if specified variable is set: test -v variable_name

Tests if specified string is empty (its length is 0): test -z string

Tests if specified string is not empty (its length is greater than 0): test -n string

Returns true if content of both specified variables is the same, returns false otherwise: test "$variable1" == "$variable2" or test "$variable1" = "$variable2"

Returns true if content of both specified variables is different, returns false otherwise: test "$variable1" != "$variable2"

Returns true if string $variable1 sorts before $variable2, returns false othewrwise: test "$variable1" < "$variable2"

Returns true if string $variable1 sorts after $variable2, returns false othewrwise: test "$variable1" > "$variable2"

Returns true if both specified integer variables are equal: test $variable1 -eq $variable2

Returns true if both specified integer variables are not equal: test $variable1 -ne $variable2

Returns true if integer variable $variable1 is less than integer variable $variable2: test $variable1 -lt $variable2

Returns true if integer variable $variable1 is less than or equal to integer variable $variable2: test $variable1 -le $variable2

Returns true if integer variable $variable1 is greater than integer variable $variable2: test $variable1 -gt $variable2

Returns true if integer variable $variable1 is greater than or equal to integer variable $variable2: test $variable1 -ge $variable2

Synonym of the test command are two square brackets separated with white character to the left and to the right. Just after the closing bracket can be also put a semicolon, for example: if test -f file_name; then is synonym to: if [ -f file_name ]; then

Negated condition below returns true if file "file_name" does not exists: if [ ! -f file_name ]; then

If conditional expression:

if condition; then
    instructions_1
else
    instructions_2
fi
If expanded conditional expression:
if condition; then
    instructions_1
elif condition_2; then
    instructions_2
elif condition_3; then
    instructions_3
...
else
    instructions_n
fi

for..in loop:

for variable in list-of-items-separated-with-character-from-$IFS; do
    instructions
done;
Instruction below generates a numerical list starting at FROM to TO with incremental step STEP: {FROM..TO..STEP} for example: {1..4..1} => 1 2 3 4 and: {1..4..2} => 1 3 Command seq below also generates a numerical list starting at FROM to TO with incremental step STEP. Generated items are separated by a new line character: seq FROM STEP TO for example: seq 1 1 4 => 1\n2\n3\n4\n and: seq 1 2 4 => 1\n3\n

for loop:

for (( counter=1; counter<=10; counter+=2 )); do
    instructions
done;
Loop through the positional variables $1, $2, ...
for variable; do
    instructions
done;

while loop:

while condition; do
    instructions
done;
The loop above processes the instructions as long as the condition evaluates to true. The example of while loop as a destination of a stream:
cat file_name |
while read line; do
    echo $line
done;
Example of while loop that write out the file line by line:
while read line; do
    echo $line
done <text_file

until loop:

until condition; do
    instructions
done;
The loop above processes the instructions as long as the condition evaluates to false.

In for, while and until loops one can use commands: continue and break.

case structure:

case value in
    pattern_1)
        instructions_1
        ;;
    pattern_2)
        instructions_2
        ;;
    ...
    *)
        default_instructions
        ;;
esac

Select command displays menu that contains items specified after in keyword and assigns selected item to a variable variable placed just after select keyword. Next it runs commands placed between do and done keywords until it encounter break statement. The selected number is stored in $REPLY variable. The prompt is set in the $PS3 variable (by default it is #? string):

select variable in item_1 item_2 ...
do
    instructions
    ...
    break
done
Example:
#!/bin/bash

clear
select variable in cap scarf gloves
do
    if [ "$variable" == "" ]; then
        echo Nothing is chosen
        continue
    fi

    echo $REPLY --- $variable
    break
done

Redirecting script fragment to the standard input of a command:

#!/bin/bash

wc -l <<_END_
line_1
line_2
line_3
_END_
The script above displays count of lines redirected to the standard input of the wc command.

$RANDOM variable generates an integer number from <1..32766> range.

Incrementing integer number variable by 1: (( i += 1 ))

Function definition:

function f_name()
{
    instructions
}

Removes function f_name: unset f_name

break instruction causes immidiately function exit. Local variables of functions are defined with use of local keyword, for example: local name="Marcin";

If a variable is defined without of local keyword then the variable is global one available from outside of the function, ex.: name="Marcin";

Saves specified function in the environment so the function is available for all child processes: export -f f_name

Variables passed to function are available in the positional parameters: $1, $2, $3, ... The count of passed function arguments is available in $# variable.

Function:

function my_function()
{
    echo "Parameters count:" $# "-" $1 $2 $3
}
can be called in following way (with parameters passed): my_function 1 "param 2" 3

Opens descriptor 3 (standard input duplicate) and 4 (standard output duplicate): exec 3<&0 4>&1

Opens descriptor 3 (file specified in $1 variable as an input) and 4 (duplikat standardowego wyjścia): exec 3< $1 4>&1

Opens descriptor 3 (file specified in $1 variable as an input) and 4 (file specified in $2 variable as an output): exec 3< $1 4> $2

Closes descriptors 3 and 4: exec 3<&- 4<&-

Reads data from descriptor 3 and writes it to descriptor 4: cat <&3 >&4

Declares simple array: FRUITS=(apple pear cherry strawberry)

Numeration of an array elements starts with 0. Below there is an access to the second array element: ${FRUITS[1]} - pear

Making an array duplication: DUPLICATE=("${FRUITS[@]}")

Creating a new array that have one element consisting of all elements of the FRUITS array separated by the first character of $IFS variable (usually space): NEW_ARRAY=("${FRUITS[*]}")

Example of declare -a (creating array-type variables): declare -a DUPLICATE='([0]="apple" [1]="pear" [2]="cherry" [3]="strawberry")' declare -a NEW_ARRAY='([0]="apple pear cherry strawberry")'

Displays count of array elements: echo ${#FRUITS[*]}

Displays size of a specified array element: echo ${#FRUITS[1]}

Displays array's content: echo ${OWOCE[*]}

Reads from standard input a line and assigns it to the line variable: read -p "Type in a line: " line

Reads from standard input two words and assigns it to the word1 and word2 variables (if there are more than two words then word2 holds all words starting from the second one): read -p "Type in two words: " word1 word2

Reads a line from specified file descriptor (here 3) and assigns data to word1 and word2 variables (according to the rule described above). If the file was already opened and one read from it, then reading from it will be continued from the current file position: read -u3 word1 word2

Catching INT (2) signal and executing commands specified in apostrophes (here displaying a message and exiting the script with error code 1): trap 'echo Script catched INT signal. Exiting the script; exit 1' INT

Executes cleaning operations after script finished its task (either after explicit call to exit command or after all commands were executed): trap 'cleanup_before_exit' EXIT

getopts command processes all options passed from the command line to a script: getopts [:]options current_option for instance.: getopts :u:h:d opt

Options argument consists of letters that can be passed to the script. If it starts from the colon then the error (passing unrecognized option or ommitting argument for an option) handling will be ceded to the script. If after a letter appears a colon (:), then the option takes an argument.
Parameter current_option (opt in the example above) in each call to getopts command contain successive option letter. Additionally in each run there are set OPTIND (option number starting from 1) and optionally OPTARG (argument for the current option, if it takes one) variables.

In the example below there is presented a way of processing options in script:

USER=
HOME_DIR=
DATE=0

while getopts :u:h:d opt; do
    case $opt in
        u) if [ -z "$OPTARG" ]; then
               echo "Username not specified" >&2
               exit 1
           else
               USER="$OPTARG"
           fi
           ;;
        h) if [ -d "$OPTARG" ]; then
               HOME_DIR="$OPTARG"
           else
               echo "Specified directory does not exists" >&2
               exit 1
           fi
           ;;
        d) DATE=1 ;;
        :) echo "Option $OPTARG require an argument" >&2
           exit 1
           ;;
        \?) echo "Unrecognized option $OPTARG" >&2
            exit 1
            ;;
    esac
done
    
echo "Username $USER"
echo "Home directory: $HOME_DIR"
if [ $DATE -eq 1 ]; then
    echo -n "DATE: "
    date
fi

If the option argument (:) was not specified or unrecognized option (\?) was passed, then the $OPTARG variable holds the option name.

Calculating arithmetic expressions: let "OUTCOME=VARIABLE_1 + VARIABLE_2 * 2" or equivalent: ((OUTCOME=VARIABLE_1 + VARIABLE_2 * 2)) In the let command or in its bracket equivalent, variable names do not have to starts with $ prefix.

For calculating boolean expressions the following syntax is used: [[ expression ]] Within the expression all variables have to be prefixed with $, ex.:

if [[ 1 < $number && $number < 10 ]]; then
    echo Number in range [2,9]
fi
Spaces around the square brackets [[ and ]] are required.

Checking if specified text matches the pattern (all spaces in the expression below are required): [[ "TEXT_OR_VARIABLE" = M* ]] ex.: NAME=Marcin
[[ "$NAME" = M* ]]
returns true, while [[ "$NAME" = m* ]] or [[ "$NAME" = a* ]] return false.

Examples of removing prefix and postfix matches from a variable:

#  - removes minimal matched prefix
## - removes maximal matched prefix
%  - removes minimal matched postfix
%% - removes maximal matched postfix
Examples: EMAIL=mzaleczny@any.domain.pl
echo ${EMAIL#m*@} => any.domain.pl
echo ${EMAIL#m*.} => domain.pl
echo ${EMAIL##m*.} => pl
echo ${EMAIL%.*} => mzaleczny@any.domain
echo ${EMAIL%%.*} => mzaleczny@any

Returns length of string variable: echo ${#EMAIL} => 23

Turns off displaying of typed in from the keyboard characters: stty -echo

Turns on displaying of typed in from the keyboard characters: stty echo