------------------------------------------------ Practice Unix/Linux Scripts - Chapters 5, 10, 11 - Part 1 ------------------------------------------------ -IAN! idallen@ncf.ca All scripts written must conform to the script_checklist.txt checklist. All user input (arguments or via "read") must be validated before being used. Do not process bad or missing input data! All scripts written must begin with a proper script header (including PATH and umask), as given in the script_checklist.txt file. All prompts for user input must appear on the terminal, even if standard output is redirected. (Do not send prompts for input into the output file!) Quote all your variables - never let the shell expand glob patterns (wildcards) unexpectedly. Test this! Pay close attention to the names and locations of input/output files. Not all of these scripts are equally difficult to write. Find the easy ones first! TimeSaver: Use filename completion in the shell to complete the names of these scripts when you want to test them or edit them. Don't keep typing the full path names of the scripts! Let your Shell do your typing for you! --) Type in all the scripts in the parts of Chapter 10 that we study (starting with "whoson"). Add the correct script headers to the scripts. Test them to make sure that they work. --) Write this executable script named "1_my_who.sh": Run "who" on ACADUNIX to show all logins, and delete from the display the logins that are by idallen. (The output must not contain idallen logins. You will need to use an option to a common Unix command so that you do *not* see lines that match a pattern.) --) Write this executable script named "4_pinger.sh": Prompt to read a host name from the script user and then read the host name. Send only 4 ping packets (a count of 4) to the host name supplied by the user. Display the exit status (return code) of the ping command. Have the script exit with that return status. Hints: - see "man ping" in the man pages - Chapter 10 Special Parameters (exit status) - on AIX, ping is not in /bin or /usr/bin; find where it is located and set the script PATH accordingly --) Write this executable script named "6_secure_directories.sh": Remove all group and other permissions on the current directory and on all immediate subdirectories of the current directory that don't begin with periods (the non-hidden directories). Do not change any files. Hints: - echo */. (see the notes for Chapters 4 and 5, and the Notes file pathnames.txt) Note: This is tricky to do correctly if the current directory has *no* non-hidden subdirectories. You need control structures from Chapter 11 to handle that case. To keep this script simple, you may assume that there will always be at least one non-hidden subdirectory. --) Write this executable script named "8_standard_error.sh": Prompt to read a line from the script user and then read the line. Display one copy of the line on standard output. Display a second copy of the line on standard error with all the characters changed to UPPER CASE. (This last item will require some thought - you can't blindly copy anything you've seen to date.) Test your script as follows: $ ./8_standard_error.sh >out If you don't see a prompt, fix your script so that the prompt does not get redirected into the file "out". The prompt should be visible, even with standard output redirected into a file. (Advice: Prompts for input should always be visible, even if output is redirected. You never want the prompt to be redirected into the output file along with the script output!) Hints: - last page of "Redirecting Standard Error" (Ch10) - in a command pipeline, which command is the one that needs to have its standard output sent to standard error? --) Write this executable script named "9_show_processes.sh": On ACADUNIX, prompt to read a text string from the script user and then read the text string. Look for that text string in the output of the "ps" command. Use both the "-f" and "-e" options to the "ps" command, so that "ps" outputs *all* the processes on the machine in a nice format. Your output will be only the lines from "ps" that contain the text string. Bonus: Fix the script so that it works even if the user enters a text string that starts with a dash. (Hint: the man page.) --) Try all the script examples that use different command interpreters (e.g. #!/bin/cat) given in the chapter10.txt file. Also try these command interpreter lines and see what they do: #!/bin/wc #!/bin/cat -n #!/bin/sort -r #!/bin/grep # Reminder: These first lines are interpreted by the Unix kernel only if the script is *executable* and you try to *execute* the file (e.g. ./script.sh). The lines are comment lines and are ignored by all Unix shells that read the file (e.g. "bash script.sh"). --) Write this executable script named "91_environment_variables.sh": Produce an output line similar to the following: The value of $HOME is: /thome/alleni for each of the shell variables: HOME, MAIL, PATH, and SHELL. (No loop is needed.) The script will generate four lines of output, showing the name and current values of each of the four shell variables. Test the script by setting your MAIL variable to be an asterisk, exporting MAIL, then running your script. Your script must show the correct value - an asterisk. (Never let shell glob patterns expand unintentionally.) --) Write this executable script named "92_UPPER_translator.sh": Prompt to read a line from the script user and then read the line. The script user should respond by entering a line that contains two file names, separated by blanks. The script will place each file name into its own shell script variable. Translate all the characters from the first file to UPPER-CASE and put the result into the second file. (Translate the file contents, not the file names!) Your script must do all the proper input validation - make sure both names are not empty, make sure the input file is a file and is readable, make sure the output file is nonexistent or writable, etc. --) Write this executable script named "93_host_finder.sh": Look for the name of the current host in the file /etc/hosts and print only the lines containing the current host name. The script must work on any machine and print the lines from /etc/hosts that match the current machine name. Hints: - the Unix "hostname" command will output the current host name - command substitution (Ch.10) will let you capture command output --) Write this executable script named "95_PATH_lister.sh": Display all the directories in your PATH variable, one per line, line numbered. Hints: - send the path into the translate command - translate colon characters into newline characters (use \n to represent a newline in the second argument to tr) - see "man cat" to learn how to line-number the output lines --) Write this executable script named "97_backwards_args.sh": Display the number of arguments found on the command line. Print an error if there are more than three arguments. Next, display the arguments from the command line, one per line, in reverse order (last to first). (Make sure you test your script with zero, one, two, and three arguments.) Warning: Make sure that shell glob characters inside the arguments do not expand when you display the arguments! --) Write this executable script named "98_sort_diff.sh": Make sure the script has exactly two arguments. Display on the screen the strings that are the first and second command line arguments to the script. Take the first argument as a file name (verify this!) and sort it into a temporary file. Take the second argument as a file name (verify this!) and sort it into a different temporary file. (Put the temporary files under the /tmp directory.) Use the "diff" command to show the differences (if any) between the two sorted files. Remove the temporary files. The script should exit with the same return code as the "diff" command, whatever that is. Warning: Make sure that shell glob characters inside the arguments do not expand when you process the arguments! --) Write this executable script named "99_pid_finder.sh": Look for the process ID number of the currently running script in the output of the "ps" command with the "-f" option. Display the matching lines preceded by line numbers. Hints: - see "man cat" for how to add line numbers Bonus: Find a way to display the first title/header line of "ps" before you display the matching lines. (Hint: - you might want to run "ps" twice in the same script, using the first run to obtain just the title line.) Bonus: If the process ID is 123, don't display lines containing 1234 or 0123. (Hint: the man page) =================== Command syntax used =================== You probably need to use most of the variables, syntax, and commands listed below to write the above scripts; though, your scripts won't necessarily use them in the way that they are shown in the list below: cat "$HOME/.bash_history" cat -b file who | cat -n date >/tmp/temp1$$ ; who >/tmp/temp2$$ ; cat /tmp/temp1$$ /tmp/temp2$$ echo "Some shell variables:" "$#" "$$" "$?" echo "$(echo one two three | tr ' ' '\n' | sort | head -1)" echo "$(grep 'pattern' file)" echo "$(hostname)" echo "$(whoami)" echo "$0" "$1" "$2" "$3" echo "HOME $HOME" "MAIL $MAIL" "PATH $PATH" "SHELL $SHELL" echo */. echo 1>&2 "$0: some error message or prompt" diff one two ; status=$? ; exit "$status" grep -e 'pattern1' -e 'pattern2' grep -e "$input" grep -v grep '^pattern' head -1 ls /usr/sbin ping -c ps -ef read var1 var2 ; echo "var1 is $var1 and var2 is $var2" tr ' ' '\n' tr ':' '\n' tr 'a-z' 'A-Z' whereis ping