cis 191: linux and unix class 3 february 11 th, 2015
TRANSCRIPT
Aside: Vim or Emacs in your shell!
• Add one of the following to your .bashrc to have basic editor commands added to your shell session!!!– set –o vi– set –o emacs
Shell Constructs in Brief
• | - Pipes• <, >, 2> - Redirections• $( ), ` ` - Command Substitution• ; , &&, || - Command Lists• & - Run in background
Variables
• var=str assigns the text str to the variable var• $var is replaced with the text stored in var• echo $var prints the text in var• Variables that have not been set are replaced with the
empty string– Kind of like the null value in Java– So, echo $notset will print a blank line
Filename Completion
• Recall Wildcards– * will match any string of text (except for hidden files)– ? will match any single character (again, except hidden files)
• Some new stuff– [chars] matches any character enclosed
• [a-z] matches the range of characters from a to z– {list} is expanded to a space-delimited term once for each item
in the list• Recall the scp command from homework 1• So, twenty-{one,two,three,four} is expanded to
– twenty-one twenty-two twenty-three twenty-four
Note on notation
• From this point forward, single line shell interactions will still be preceded by a $, as before.– Input to the shell and resulting output will be on consecutive
lines
• Longer pieces of shell scripting will be written in consolas, but not preceded by a $.– Output will be displayed separately
Expansions Save Keystrokes
• A simple way to list all filesfor i in *; do
echo $i is a filedone
• From now on, expect to see this * notation instead of $(ls).
• So, to copy all CIS191 lecture notes to their own directory, just do– $ mkdir CIS191 && cp cis191* CIS191
An If and test example!
if [ $SHELL = /bin/bash ]then
echo ‘You are using bash’else
echo ‘Your shell is not /bin/bash’fi
We can inline these statements with ;
• Equivalently… (and this holds similarly for for loops and other like constructs)
$ if [ $SHELL = /bin/bash ]; then echo ‘You are using bash’; else echo ‘Your shell is not /bin/bash’; fi
• This is bad form when writing your scripts to save and distribute or execute later or submit for a homework assignment!
• But it can be useful when writing a one liner in the command line (and you are not intending to save it)
test
• A simple test binary which is often found with if.• Often, we’ll see test run via its alias, the [ ] operator
– This is usually a shell command, not a program… (fyi)
• Note that all the following commands can be run by typing [ my arguments ] or test my arguments– It’s really just a matter of style– I’d recommend using the square braces in an if statement for
syntactic sugar
A couple more test notes…
• You have to write the notation exactly as we showed it here!
• [-e file] IS NOT THE SAME as [ -e file ]– You must have the space separating the brackets and other text!
• Also, to reiterate, the brackets are just an alias for the test command. To test for file existence, you could also type– test –e file
If and Test example
hours=$(date +%H)if [ $hours –lt 12 ]; then
echo It is before noon.fi
Note the semicolons before then in this usage case
Test Conditions (Strings)
• [ $str1 = $str2 ] => success if str1 is equal to str2• [ $str1 != $str2 ] => success if str1 is not equal to str2• [ -z $str ] => success if the string empty (null)• [ -n $str ] => success if the string is nonempty (not null)• [ $str1 < $str2 ] => success if str1 is less than str2 (alpha)• [ $str2 > $str2 ] => success if str1 is greater than str2
Test Conditions (numbers)
• The following convert the strings m and n to numbers before doing tests on them
• [ $m –eq $n ] => success if m is equal to n• [ $m –ne $n ] => success if m is not equal to n• [ $m –lt $n ] => success if m is less than n• [ $m – le $n ] => success if m is less than or equal to n• [ $m –gt $n ] => success if m is greater than n• [ $m –ge $n ] => success if m is greater than or equal to n
Test Conditions (files)
• [ -e filename ] => success if filename names a file• [ -d dirname ] => success if dirname names a directory• [ -r filename ] => success if filename names a file for
which the current user has read permissions• [ -o filename ] => success if filename names a file which
the current user owns• There are other options as well
– Checking write/execute permissions, filetype, etc
• See test(1) man page for more details– man test
How do we define “true” and “false”?
• In bash, “true” is a success code• And “false” is an error code• A success code is always 0
– And anything else is an error…
Some standard exit codes
• 0 – normal (true)• 1 – catchall for any general error• 2 – wrong usage• 126 – file is not executable• 127 – file not found• 128 – program killed by ^C
An example of using error codes
• Good for reporting errors
if rm file; thenecho Removal worked.
elseecho Removal failed.
fi
If – diff edition
#!/bin/sh#Say $1 is the usernameif diff $1/homework reference-answer; then
response=‘Incorrect answer!’else
response=‘Correct answer!’fiecho $response >> $1/grade.txt
If: grep edition
• Our old friend grep returns success or failure too…
#!/bin/sh# Assume $1 is the usernameif grep ‘pants’ myfile.txt; then
echo ‘Your file contains pants!’else
echo ‘Clothe your file please.’fi
For: A foreach construct
• Use for loops to repeat an iteration over a set of values• The general form is as follows:
for i in listdo
commands…done• i is set to each of the items in list, in turn• commands is a list of commands to execute
For: example
for i in one two red bluedo
echo $i fishdone
The results are
one fishtwo fishred fishblue fish
Internal Field Separator (IFS)
• This is how the shell knows how to split a string of text into a list which can be iterated through
• Make sure not to change this globally– Why might this be a bad idea?
• Change IFS locally only– Good for iterating through a comma-separated line, or a line
separated by semicolons… (etc)– Save old value of IFS
• $ OLDIFS=$IFS• $ IFS=‘,’• <DO STUFF>• $ IFS=$OLDIFS
Useful: Debug Mode
• You can run any script with – $ bash –x script.sh
• to enter debug mode– This will show each command being run (after substitutions and
aliases, and in a loop iteration
If, For, and Test: Better Together!!
• What does this do?
for i in $(ls)do
if [ -d $i ]echo $i is a directory
fidone
If, For, and Test: Better Together!!
• What does this do?
for i in $(ls)do
if [ -d $i ]echo $i is a directory
fidone
It lists directories, but not other types of files (and adds some flavor text to boot)
While – Another way to Loop!
• The while loop repeats an action while a condition is true– Sound familiar?
while condition do
commandsdone
Until – do until a condition is satisfied
• The until loop repeats an action until a condition is satisfied
until conditiondo
commandsdone
Wait until a minute is finished
while [ $(date +%S) != 00 ]; dosleep 1
doneecho A new minute just started.
• or, equivalently
until [ $(date +%S) == 00 ]; dosleep 1
doneecho A new minute just started.
read – User input
• This command allows you to get user input for your scripts
• $ read x• hey there• $ echo $x
– hey there
• $ read x y• hey there• $ echo $x and $y
– hey and there
While + read
• You can use the read function in conjunction with a while loop for short hand (read returns a status code)– read returns success if it gets input, and gives an error code if it
receives an EOF (^D) on a blank line.
while read xdo
echo You input ${x}.done
So, to exit a while read loop…
• We have a couple of options• We can kill the program
– ^C, ^\
• We can give read a zero-length string– ^D (EOF) on an empty line– Why won’t just pressing enter work?
• We can break out of the loop programmatically on some input
break and continue
• Basically the exact same functionality as in standard curly brace languages (c, java)
• break– If this command is encountered, then the script will exit the
innermost loop
• continue– If this command is encountered, then the loop will stop
execution of the loop body and skip to the next iteration of the loop
In example
while read x; do if [ $x == 'quit' ]; then break elif [ $x == 'skip' ]; then continue fi echo You entered ${x}.done
Redirection and while read loops
• Consider the following
while read line; doecho $line
done < myfile.txt
Leveraging read’s break on newline
• Since read breaks on the newline, we can pipe the contents of any file we like into the while-read loop’s standard input– This provides a very convenient way to loop through the lines in
a file…
Arithmetic in Bash
• As we discussed, the shell primarily operates on strings• But if you’ve ever programmed anything ever, then you
know that sometimes arithmetic is necessary…• In bash, arithmetic is placed inside $(( )).• For example
– $ echo The UID after yours is $(($UID + 1))– $ echo Six times nine is $((6 * 9))
Arithmetic Example
• Suppose you wanted to count the subdirectories using bash arithmetic
count=0for i in *; do
if [ -d $i ]; thencount=$(($count + 1))
fidoneecho There are $count subdirectories.
Bash and floating point arithmetic
• Bash doesn’t do floating point arithmetic– Just does typical integer truncation if an expression would
evaluate to a decimal point
Curly Braces for Dereferencing variables
• $ foo=herp• $ echo ${foo} • herp
• Considered to be good practice in all cases– Didn’t go into this last class for clarity…
• Also useful to expand variables when we want to append text to them without any whitespace…
• $ echo ${foo}derp• herpderp
Bash arrays
• It’s possible to define arrays in bash, too!– Though they are more like maps or dictionaries than arrays
• $ myarr[1]=first• $ myarr[2]=second• $ myarr[me]=ohmy
Dereferencing arrays requires { }
• Unlike other variables, dereferencing an array requires the use of curly braces!
• $ echo ${myarr[1]}• first• $ echo ${myarr[1]}not${myarr[2]}• firstnotsecond• $ echo me${myarr[me]}• meohmy• $ echo $myarr[me]• ohmy[me] (what?? – remember to use curly braces!)
Arrays are not backwards compatible!
• It’s important to note that POSIX compliant scripts should not make use of the array notation!
• Older interpreters such as sh and dash do not support arrays or the array syntax
• In general, if you are using arrays, you should consider writing the script in another language…
• Including them for completion more than as advice
Script Arguments
• Your scripts can accept CLI arguments too!– $1 is the first parameter to a script– $2 is the second parameter to a script
• and so on and so on…– $0 is the name of the script (the filename)– $@ is the list of arguments (as a bash array)– $* is also the list of arguments (as a space delimited string)– $# is the number of arguments passed to the script
shift operator for arguments
• Calling shift in a bash script will pop the first argument off the argument list, making $1=$2, $2=$3, and so on
• Another way to iterate through all input arguments!while [ $1 ]; do
stuffshift
done
Shell Functions
• You can place code that needs to be repeated in a function (just like in other programming languages)– Shell functions can be though of like sub-scripts– If you define a function in the current shell environment, then
the shell will tab complete the function for you!
name (){
commands}
Shell Functions
• Can also be written in one line (like anything else in bash)– $ name() { commands; }
• Arguments to functions are retrieved the same way they are to scripts– So, $1 is the first argument, $# is the number of arguments…
Kaboom!
• $ () {: | :&}; :• Well, “:” is a valid name in bash… so it’s basically just a
function name. Let’s try replacing it with “bomb”.• $ bomb() {bomb | bomb&}; bomb
• Does this make things any clearer?
Breakdown
• This statement defines a function, :, which runs itself in the background twice– Then we call that function
• This is the canonical bash fork bomb• Don’t run this on Eniac.
– They’ll know it was you.
• Don’t run it on your own computer either. You’ll need to restart it (or the virtual machine).