Lab 02: Basic Bash Scripting (SOLUTIONS)
Table of Contents
Task 1
The file /etc/passwd
contains all the login information (not
passwords) for users on the system. Each line looks a little like
this:
username groupid home dir
| | |
v v v
aviv:x:35001:10120:Adam Aviv {}:/home/scs/aviv:/bin/bash
^ ^ ^
| | |
uid name default shell
Write a script, allusers.sh
, that will parse the /etc/passwd
file and print a list of all the usernames.
Place your allusers.sh
script in your scripts
folder
Solution
#!/bin/bash cut -d ":" -f 1 /etc/passwd
Task 2
Write a script, getname.sh
that takes a username as an argument
and prints the full name of that use. Here is some sample output.
#> ./getname.sh aviv
Adam Aviv {}
#> ./getname.sh m159999
Midn Midshipmen Class 15 Test {}
Because you want to match precise usernames, you can use the
following grep
regular expression in your script:
grep "^USERNAME:"
Where USERNAME
is replaced by the username you are searching
for. If the user is not found, your script can print nothing.
For additional tests, you can compare your program to the finger
command which does something similar. See the manual for more
detail.
Solution
#!/bin/bash grep "^$1:" /etc/passwd | cut -d ":" -f 5
Task 3
Write a script, getsize.sh
, which takes a path as an argument and
prints out the size of the file/dir at that path. Your script must
do error checking. Here is some sample output:
#>./getsize.sh
ERROR: Require file
#>./getsize.sh adadf
ERROR: File adadf does not exist
#>./getsize.sh empty.txt
0
#>./getsize.sh larger.txt
5000
You should be able to use a cut
, ls
, and/or wc
to get the
information you need. All errors should be written to stderr
such
that:
#> ./getsize.sh badfile > /dev/null
ERROR: File badfile does not exist
You may also find it useful to use the tr
command. Consult the
man page for more details, but tr
is used for translation,
substituting one string for another. The squeeze option -s
, in
particular, could be useful to get rid of extra whitespace so that
your cut
fields are more consistent.
Solution
#!/bin/bash# # getsize.sh path # # Print the path if [ $# -lt 1 ] then echo "getsize.sh: ERROR: Require file" 1>&2 elif [ ! -e $1 ] then echo "getsize.sh: ERROR: File $1 does not exist" 1>&2 else ls -l $1 | tr -s ' ' | cut -d " " -f 5 fi
Task 4
Create a script called getallsizes.sh
, which takes in any number
of files on the command line and prints their sizes as
follows. Here's some sample usage:
#> ./getallsizes.sh empty.txt isbigger.sh larger.txt
empty.txt 0
isbigger.sh 204
larger.txt 5000
#> ./getallsizes.sh empty.txt BADFILE larger.txt
empty.txt 0
getallsizes.sh: ERROR: File BADFILE does not exist
larger.txt 5000
#> ./getallsizes.sh empty.txt BADFILE larger.txt 2>/dev/null
empty.txt 0
larger.txt 5000
(HINT) Check out the man page for echo
to print without a
trailing new line so you can align the file name with their size.
Solution
#!/bin/bash# # getallsizes.sh [path [path [..]]] # # Print the size of all the files in the path for f in $* do if [ ! -e $f ] then echo "getallsizes.sh: ERROR: File $f does not exist" 1>&2 else echo -n "$f " ls -l $f | tr -s ' ' | cut -d " " -f 5 fi done
Task 5
Write a script, isbiggerthan.sh
, which takes a path and a size
and determines if the file or directory is bigger (or equal to) the given
size. Here is the usage:
isbiggerthan size path
And here is some sample output
#> ./isbiggerthan.sh
isbiggerthan.sh: ERROR: Require path and size
#> ./isbiggerthan.sh 1
isbiggerthan.sh: ERROR: Require path and size
#> ./isbiggerthan.sh 0 empty.txt
yes
#> ./isbiggerthan.sh 2 empty.txt
no
#> ./isbiggerthan.sh -1 empty.txt
isbiggerthan.sh: ERROR: Require a positive number for -1
#> ./isbiggerthan.sh ad empty.txt
isbiggerthan.sh: ERROR: Require a number for ad
#> ./isbiggerthan.sh 0 doesnotexist
isbiggerthan.sh: ERROR: File doesnotexist does not exist
#> ./isbiggerthan.sh 3000 larger.txt
yes
#> ./isbiggerthan.sh 10000 larger.txt
no
Note, checking if a variable is a number is non trivial. Here is some simple code to do that:
if [ "$var" -eq "$var" ] 2> /dev/null # check for a number pipe error to /dev/null then echo "it's a number" else echo "it's *not* a number" fi
Solution
#!/bin/bash# # isbiggerthan.sh size path # # Print the path if [ $# -lt 2 ] then echo "isbiggerthan.sh: ERROR: Require path and size " 1>&2 exit 2 fi if [ "$1" -eq "$1" ] 2> /dev/null # check for a number then echo -n #it's a number else echo "isbiggerthan.sh: ERROR: Require a number for $1" 1>&2 exit 3 fi if [ $1 -lt 0 ] then echo "isbiggerthan.sh: ERROR: Require a positive number for $1" 1>&2 exit 4 fi if [ ! -e $2 ] then echo "isbiggerthan.sh: ERROR: File $2 does not exist" 1>&2 exit 5 fi size=$(ls -l $2 | tr -s ' ' | cut -d " " -f 5) if [ $size -ge $1 ] then echo "yes" exit 0 else echo "no" exit 1 fi
Task 6
Update your isbiggerthan.sh
script to exit with different status
codes dependent on if the file is bigger than the size or if there
is an error. For example:
- exit 0 : if the file is bigger (or equal) to the size
- exit 1 : if the file is not bigger (or equal) to the size
- exit 2 : if not enough arguments
- exit 3 : did not receive a number for size
- exit 4 : recieved a negative number for size
- exit 5 : file does not exist
Once complete, now create a new script isbiggerthanall.sh
which
takes the following arguments:
isbiggerthanall.sh size path [path [...]]
which outputs all the files provided that are bigger than the
size. Your script must call your isbiggerthen.sh
script and
check the exit status to determine the result and output.
Here is some sample output:
isbiggerthan size path
And here is some sample output
#> ./isbiggerthanall.sh 1
isbiggerthanall.sh: ERROR: Require a size and at least one file
#> ./isbiggerthanall.sh 1 empty.txt
#> ./isbiggerthanall.sh 0 empty.txt
empty.txt
#> ./isbiggerthanall.sh 0 larger.txt
larger.txt
#> ./isbiggerthanall.sh 6000 larger.txt empty.txt
#> ./isbiggerthanall.sh 0 larger.txt empty.txt
larger.txt
empty.txt
#> ./isbiggerthanall.sh 0 *
empty.txt
emtpy.txt
getallsizes.sh
getsize.sh
isbigger.sh
isbiggerthan.sh
isbiggerthanall.sh
larger.txt
#> ls *.sh | xargs ./isbiggerthanall.sh 100
getallsizes.sh
getsize.sh
isbigger.sh
isbiggerthan.sh
isbiggerthanall.sh
#> ls *.sh | xargs ./isbiggerthanall.sh 300
isbiggerthan.sh
isbiggerthanall.sh
(On Your Own) Google and learn about case statements for bash, and use a case statement to check the exit condition.
Solution
#!/bin/bash # isbiggerthan.sh size [path [path [...]]] # # print the files that are bigger than the size if [ $# -lt 2 ] then echo "isbiggerthanall.sh: ERROR: Require a size and at least one file" 1>&2 exit 2 fi i=1 for f in $* do if [ $i -ne 1 ] #not for first argument which is the size then ./isbiggerthan.sh $1 $f 2>&1 > /dev/null case $? in 0) echo $f ;; 1) echo -n ;; 2) echo "isbiggerthanall.sh: ERROR: isbiggerthan.sh" 1>&2 ;; 3) echo "isbiggerthan.sh: ERROR: Require a number for size not $1 " 1>&2 ;; 4) echo "isbiggerthan.sh: ERROR: Require a positive number " 1>&2 ;; 5) echo "isbiggerthan.sh: ERROR: File $f does not exist" 1>&2 ;; *) echo "HUH? $?" ;; esac fi let i++ done