bash Tests and Looping Administrative Shell Scripting COMP2101 Fall 2017
Command Lists A command is a sequence of commands separated by the operators ; & && and ; is used to simply execute commands in order with no dependence on each other echo "Files in current directory: " ; ls & is used to put a command into the background, background tasks can be viewed with the jobs command sleep 60 & sleep 120 & sleep 30 & jobs && and cause the command on the right to be run only on the success and failure respectively of the command on the left ls && echo "ls was successful" ls /flooble echo "ls failed"
Command Pipeline A command pipeline is a sequence of commands separated by the character The character causes the output (/dev/stdout) of the command on the left of the to be connected to the input (/dev/stdin) of the command on the right The exit status of a pipeline is the exit status of the last command in the pipeline echo -n "Number of non-hidden files in this directory: " ; ls wc -l echo "Process count by username:" ; ps -eo user --no-headers sort uniq -c ls /flooble wc -l && echo "Worked!"
Practice Create the script below Run the script without creating a variable named MYVAR in your current shell Try it with MYVAR existing but empty, then existing with data in it (don't forget to export it!) #!/bin/bash # This script demonstrates testing if a variable named MYVAR exists and whether it is empty # It is expected that you use this script to test if MYVAR is inherited from a parent process # since it is not created or modified in this script [ -v MYVAR ] && echo "The variable MYVAR exists" [ -v MYVAR ] echo "The variable MYVAR does not exist" [ -v MYVAR ] && [ -n "$MYVAR" ] && echo "The variable MYVAR has data in it" [ -v MYVAR ] && [ -z "$MYVAR" ] && echo "The variable MYVAR is empty"
Compound Commands Using pipelines, s, and exit status, we can construct more complex commands We can use the exit status of the test ( or [ ) command, and the [[ expression to perform commands based on the results of evaluating expressions Conditional execution can be done in more sophisticated ways using the if, while, for, and case commands
Exit Status Every process that runs, produces an exit status when it ends, either intentionally using the exit [status] command, or automatically due to script bailout, or end of file, or signal reception The shell can access that status using the special variable? Exit status 0 normally means successful completion Any time a command might fail and cause problems, your script should be doing something to recognize and deal with the possible failure echo $? [ $? = "0" ] handle error
User Input The read command can be used ask for user input and assign it to a variable You should always validate the input a user gives Always think about what happens if a user just hits enter read -p Enter something: myvar [ -n "$myvar" ] echo "You didn't give me any input" read -p "Enter 3 colours: " colour1 colour2 colour3 [ -n "$colour1" -o -n "$colour2" -o -n "$colour3" ] echo "Need 3 colours" read -s -p "Password: " passwd read -n 1 -p "[Y/n]: " choice [[ "$choice" =~ [ynyn] -z "$choice" ]] echo "Must enter a y, n, or enter" [ $(expr match "$choice" '^[ynyn]$') = 1 -o -z "$choice" ] echo "Must enter a y, n, or enter"
If Command Action can be taken, or not taken, based on the exit status of a command The test command can evaluate unary or binary expressions, so it can be a very useful command for the For a of available expression operators, refer to the man page if ; then else fi if [ expr ]; then fi
Testing Data We can do unary tests to determine if variables exist using -v varname, if strings have anything in them using -n string or -z string We can do binary tests comparing string data to other values using =,<,>,!= including static values We can do binary tests comparing integer data using -eq, -ne, -lt, -le, -gt, -ge This can be used to validate user input as well as test data retrieved from elsewhere in the system
Testing Files We can do unary tests for file existence (-e), type (-f,- d,-h,-p,-b,-c,-s), permissions (-r,-w,-x,-k,-u), ownership (-O,-G), size (-s), modification (-N), and whether a file is an open terminal device (-t fd) We can do binary tests on files based on their dates (- nt, -ot), and determine if two filenames are hard linked (-ef)
Practice What bash tests might you use for each of the following? Create a test for each of them. (e.g. file=/etc/resolv.conf ; [ -e "$file" ] && echo "$file exists" ) Does the /etc/resolv.conf file exist Is /bin/ls executable Is /tmp a directory Is /etc/hosts a directory Can you read /etc/shadow as an ordinary user Can you write /etc/network/interfaces as an ordinary user Is /bin/passwd setuid Which is newer, /etc/hosts or /etc/resolv.conf Is /bin/pidof a symbolic link or a regular file
Practice Create a script to test the following: (e.g. if [ -v SHELL ]; then echo "SHELL exists" ; else echo "SHELL does not exist" ; fi ) Does the variable SHELL exist Does the variable FLOOBLE exist Is anything assigned to $USER Is there anything assigned to $FLOOBLE a=1;b=01;c=02 Are $a and $b equal to each other alphabetically or numerically Which of $a and $c is less than the other, numerically and alphabetically arr=(a b c d) Test if $arr has more or less than one element
While Command A can be executed repeatedly based on the exit status of another The break or continue or exit commands can be used in the do to get out of a loop early while ; do done
Practice Use a while loop to display the contents of the interfaces and ips arrays from the lab 2 script Get a random number from 1 to 10, then use a while loop to ask the user for a number from 1 to 10 repeatedly until they guess your number correctly, exiting early if the user does not make a valid guess Modify the guessing game to give the user hints about whether to go higher or lower after each guess they make
For Command The for command allows repeated execution of a either substituting values from a word in a variable or by evaluating expressions for varname in word; do done for (( initial expression; test expression; loop expression )); do done
Practice Use a word for loop to display the contents of our animals arrays from the getanimal.sh script, the loop should iterate over the colour names and use them to display the animals with their colours Get a number of rolls from the user from 1 to 5 for some virtual dice, then use the expression for loop to roll a pair of virtual dice that many times, displaying the results of each roll
Case Command The case command allows execution of a based on the value of a variable or word case $var in pattern ) ;; pattern pattern ) ;; * ) ;; esac