Unix Shell Scripts
What are scripts ?
• Text files in certain format that are run by another program • Examples:
– Perl – Javascript – Shell scripts (we learn c-shell scripts)
How they differ from C programs ?
• C programs are compiled into machine code (executables) • Executables are not portable, but they run faster (no translation during runtime)
What to use ?
• Use scripts for lightweight operations:
– – – – Simple manipulations on files Sending mails Network communication Rapid development
• Use c programs for:
– – – –
CPU bound computations Complex data structures Critical time applications Embedded applications
Some useful c-shell commands
• • • • • • • • • head / tail – returns first / last lines of a file echo – print command sort – used to sort files in lexicographic order cat – concatenate files and print grep – find regular expressions in files find – find files by criteria wc – word count on files diff - find differences between files basename / dirname – extract file / directory name from full path • touch – change file timestamp • mail – sending mail • whereis – locate program
Redirection and pipes
prog redirection file
• • • • • > >> >& >>& < : redirect stdout : append stdout : redirect stdout and stderr : append stdout and stderr : redirect stdin
prog1 pipe prog2
• • & : redirect stdout of prog1 to stdin of prog2 : same, with stdout and stderr
How to write a c-shell script
• Edit the code file (no mandatory extension) • Make sure the first line in the file is: #!/bin/csh –f (for c-shell scripts) #!/bin/awk –f (for awk scripts) • Add executable permission: chmod +x filename
#!/bin/csh –f ################ #simple_example # ################ # We can define variables and print their values set course = soft1 echo $course # We can do the same for arrays set names = ( Danny Dina Eyal Ayelet Ori Neta ) echo $names echo $#names # size of array echo $names[2] # the second element echo $names[2-] # starting from the second element echo $names[-2] # until the second element echo $names[2-3] # elements 2,3
# '@' at the beginning of the line - treat as an arithmetic expression and not # as a string @ num = 17 echo $num @ num -= 3 echo $num @ num *= 14 echo $num # if we want to assign the value of a command to a variable set chars = `wc -l ./simple_example` echo $chars # accessing program parameters echo The program name is : $0, the first parameter is $1 and the second is $2 echo The number of parameters \(not including program name\) is $#argv
Loops
• foreach identifier (set) ... end • while (condition) ... end
Conditional statements
• if condition then ... endif • switch (value) case value1: breaksw ... default: endsw
Testing files attributes
• if -op file_name -r -w -x -e -o -f -d -l : read access : write access : execute access : existence : ownership : plain file : directory : link
#!/bin/csh –f ######## # sum # ######## if $#argv == 0 then echo Usage: $0 num1 [num2 num3 ...] exit 1 endif @ sum = 0 foreach number($argv) @ sum += $number end echo The sum is : $sum @ average = $sum / $#argv @ remainder = $sum % $#argv echo The avergae is: $average\($remainder\)
#!/bin/csh -f ############ # sort_files # ############ if $#argv == 0 then echo USAGE: $0 file_names_to_sort echo This command writes on the original files \!\!\! exit 1 endif foreach file($argv) sort $file > $file.tmp mv $file.tmp $file end
#!/bin/csh -f # Biggest_file # INPUT: Directory name # OUTPUT: The file with the biggest number of characters in the given directory if $#argv == 0 then echo USAGE: $0 directory_name exit 1 endif if -d $1 then @ max = 0 foreach file($1/*) if (-r $file && -f $file) then set wc_out = `wc -c $file` if ($wc_out[1] > $max) then set biggest_file = $wc_out[2] @ max = $wc_out[1] endif else if !(-r $file) then echo $file unreadable endif end echo The biggest file is $biggest_file echo The number of characters is $max else echo $1 is not a directory endif
#!/bin/csh -f # Modulo3 # INPUT: sequence of integer numbers separated by \n terminated by 0 # OUTPUT: prints the value of each number modulo 3 set num = $< while ($num != 0) @ modulo = $num % 3 switch ($modulo) case 0: echo 0 breaksw case 1: echo 1 breaksw case 2: echo 2 breaksw default: endsw set num = $< end
Retrieving returned values
• Returned values (by return, exit) are stored in status environment variable • The script:
#!/bin/csh -f ./prog if $status != 0 then echo "Error occured!" endif
runs prog (from current dir) and reports whether an error occurred.
awk
• Useful utility for file manipulation
For details see :
http://www.gnu.org/manual/gawk-3.1.1/gawk.html
#!/bin/awk -f BEGIN { stud_num = total = high_stud_num = total_high = 0} NF != 3 { print "error in line", FNR, ":", $0 next } { ++stud_num total += $3 if ($3 > 80){ total_high += $3 ++high_stud_num } } END { print "Number of students: ", stud_num print "Avergae grade is: ", total / stud_num print "Average of high grades is: ", total_high / high_stud_num}
Running with input : Ron 033453671 91 Yael 034567832 73 Ran 040478124 100 Yoav 060381253 95 Tal 045623141 78 90
Output is : error in line 5 : Tal 045623141 78 90 Number of students: 4 Avergae grade is: 89.75 Average of high grades is: 95.3333