Unix ja shell-ohjelmointi 2001, demo 3 Unix ja shell-ohjelmointi 2001, demo 3 mallivastaukset

    1. find /var -type f \( -perm o+w -o \( \( -group staff \
      	-o -group users \) -perm g+w \) \)
      
    2. find ~/tmp \( -type d -name keep -prune \) \
      	-o \( -type f -atime +7 -exec rm {} \; \)
      
      tai
      find ~ -type f -atime +7 | grep -v /keep/ | xargs rm -f 
      
      Kumpikaan noista ei poista hakemistoja (tehtävä oli siinä ehkä hiukan epäselvä).

    3. #! /bin/sh
      cd $1
      find . ! \( -name '*.o' -o -name a.out -o -name core \) |
      while read p ;do
        if [ -d $p ] ;then mkdir -- $2/$p
        else cp -- $p $2/$p 
        fi
      done
      

  1. Tehtävänmäärittely oli hieman tulkinnanvarainen loppujen käsittelyn suhteen, tarkoitus oli että argumenttien loputtua tehdään vielä yksi tiedosto johon jämät jäävät.

    #! /bin/sh
    
    prefix=x
    while getopts :i:s: opt
      do case "$opt" in
       i) exec <"$OPTARG" ;;
       s) prefix="$OPTARG" ;;
       ?) echo "invalid option -$OPTARG" >&2
        exit 1 ;;
      esac
    done
    shift $((OPTIND - 1))
    
    case "$*" in
      *[!0-9\ ]*) echo "invalid argument" >&2 
    	exit 2;;
    esac
    
    count=1
    while [ $# -gt 0 ] ;do
      lines=$1
      while [ "$lines" -ne 0 ] && read -r line ;do
        printf "%s\n" "$line"
        lines=$((lines-1))
      done >$prefix.$count
      count=$((count+1))
      shift
    done
    cat >$prefix.$count
    
    exit 0
    

    Tämä onnistuu sediä käyttäen paljon nopeammin (jopa 100 kertaa!):

    #! /bin/sh
    
    prefix=x
    while getopts :i:s: opt
    do
      case "$opt" in
       i) exec <"$OPTARG" ;;
       s) prefix="$OPTARG" ;;
       ?) echo "invalid option -$OPTARG" >&2
          exit 1 ;;
      esac
    done
    shift $((OPTIND - 1))
    
    count=1
    END=0
    CMD=
    for i in "$@" ;do
      case "$i" in
        *[!0-9]*) printf "invalid argument: '%s'\n" "$i" >&2 
    	      exit 2;;
      esac
      START=$((END+1))
      END=$((START + i - 1))
      CMD="$CMD
    ${START},${END}w $prefix.$count"
      count=$((count+1))
    done
    CMD="$CMD
    $((END+1)),\$w $prefix.$count"
    
    sed -n "$CMD"
    
    exit 0
    
    Tuo saattaa tosin epäonnistua jos tiedosto pitää jakaa yli 9 osaan (riippuu sedin versiosta).

  2. Tässä on luontevinta käyttää evalia:
    #! /bin/sh
    while getopts :i:o: opt
    do case "$opt" in
      i) exec <"$OPTARG" ;;
      o) exec >"$OPTARG" ;;
    esac
    done
    shift $((OPTIND - 1))
    
    OLDIFS="$IFS"
    IFS='|' 
    line="$*"
    IFS="$OLDIFS"
    eval "$line"
    exit 0
    

    mutta käy se ilmankin:

    #! /bin/sh
    while getopts :i:o: opt
    do case "$opt" in
      i) exec <"$OPTARG" ;;
      o) exec >"$OPTARG" ;;
    esac
    done
    shift $((OPTIND - 1))
    ${1:-cat} | ${2:-cat} | ${3:-cat} |
    ${4:-cat} | ${5:-cat} | ${6:-cat} |
    ${7:-cat} | ${8:-cat} | ${9:-cat}
    
    Tämä on sikäli huono ratkaisu että se käynnistää turhia prosesseja.

    1. #! /bin/sh
      oldid=
      oldpw=
      olduid=
      oldgid=
      oldname=
      oldjunk=
      sort -t: -k1,1 -k3,3 -k5,5  $1 $2 |
      while IFS=: read id pw uid gid name junk
      do
        if [ "$id" = "$oldid" ] && [ "$uid:$name" != "$olduid:$oldname" ]
        then
          printf "%s:%s:%s:%s:%s:%s\n" "$oldid" "$oldpw" "$olduid" "$oldgid" "$oldname" "$oldjunk"
          printf "%s:%s:%s:%s:%s:%s\n" "$id" "$pw" "$uid" "$gid" "$name" "$junk"
        fi
        oldid="$id"
        oldpw="$pw"
        olduid="$uid"
        oldgid="$gid"
        oldname="$name"
        oldjunk="$junk"
      done
      

    2. #! /bin/sh
      TMP1=pw1$$
      TMP2=pw2$$
      sort -t: -o $TMP1 $1 
      sort -t: -o $TMP2 $2 
      join -t: -o 1.1,1.3,1.5,2.3,2.5 $TMP1 $TMP2 |
      while IFS=: read id uid1 name1 uid2 name2 ;do
        if [ "$uid1" != "$uid2" ] || [ "$name1" != "$name2" ]
        then printf "%s,%s,%s,%s,%s\n" "$id" "$uid1" "$name1" "$uid2" "$name2" 
        fi
      done
      rm $TMP1 $TMP2
      
      tai
      #! /bin/sh
      TMP1=pw1$$
      trap "rm $TMP1" 0
      sort -t: -o $TMP1 $1 
      sort -t: $2 |
      join -t: -o 1.1,1.3,1.5,2.3,2.5 $TMP1 - |
      grep -v '.*:\(.*\):\(.*\):\1:\2$' |
      tr : ,
      

  3. Käyttäen bc:tä ja jokaiselle luvulle omaa lukkotiedostoa:
    #! /bin/sh
    case "$1" in
      *[!0-9]*|'') printf "'%s' is not an integer.\n" "$1" >&2
    	exit 1 ;;
    esac
    
    MYDIR=./fact
    DATAFILE=fact.$1
    LOCKFILE=$DATAFILE.lock
    mkdir -p $MYDIR 
    cd $MYDIR
    
    set -C
    until >$LOCKFILE
    do sleep 5
    done
    trap "rm -f $LOCKFILE" 0
    
    if [ ! -f $DATAFILE ]
    then
      fact=$(printf "f=1;for (i=2; i<=%s; i++) f=f*i; f\n" $1 | bc)
      count=0
    else
      read junk junk fact junk count junk <$DATAFILE
    fi
    count=$((count+1))
    
    printf "%s! = %s computed %d times before\n" "$1" "$fact" "$count" | tee $DATAFILE
    
    exit 0
    

    tai käyttäen vain shellin aritmetiikkaa (joka rajoittaa toiminnan 12:een) ja yhtä tiedostoa kaikille luvuille:

    #! /bin/sh
    case "$1" in
      *[!0-9]*|'') printf "'%s' is not an integer.\n" "$1" >&2
    	exit 1 ;;
    esac
    LIMIT=12
    if [ $1 -gt $LIMIT ] ;then
      printf "Sorry, I can't handle numbers bigger than %d.\n" $LIMIT >&2
      exit 2
    fi
    
    MYDIR=./fact
    DATAFILE=factors
    LOCKFILE=$DATAFILE.lock
    TMPFILE=$DATAFILE.tmp
    mkdir -p $MYDIR 
    cd $MYDIR
    
    set -C
    until >$LOCKFILE
    do sleep 5
    done
    trap "rm -f $LOCKFILE" 0
    
    [ -f $DATAFILE ] || printf "0 1 0\n" >$DATAFILE
    
    exec 3>&1 <$DATAFILE >$TMPFILE
    while read number factorial count 
    do
      last=$number
      lastfact=$factorial
      if [ $number = $1 ] ; then
        printf "%d! = %d, computed %d times before\n" $1 $factorial $count >&3
        count=$((count+1))
      fi
      printf "%d %d %d\n" $number $factorial $count
    done 
    
    number=$((last+1))
    factorial=$lastfact
    
    if [ $number -lt $1 ] ;then
      while [ $number -lt $1 ] ;do
        factorial=$((factorial * number))
        printf "%d %d %d\n" $number $factorial 0
        number=$((number+1))
      done 
      factorial=$((factorial * number))
      printf "%d %d %d\n" $number $factorial 1 
      printf "%d! = %d, computed %d times before\n" $1 $factorial $count >&3
    fi 
    
    mv $TMPFILE $DATAFILE
    
    exit 0
    

  4. #! /bin/sh
    # daemon starter/stopper script
    abort() {
      printf "%s: %s\n" "$0" "$1" >&2
      exit ${2:-1}
    }
    set -a
    MYDIR=/tmp/puu
    PIPE=$MYDIR/pipe
    PIDFILE=$MYDIR/pid
    DAEMON=./6daemon
    mkdir -p $MYDIR || abort "cannot create $MYDIR" 1
    
    case "$1" in
      start)
    	[ -f $PIDFILE ] && kill -0 $(cat $PIDFILE) &&
    		abort "daemon already running" 7
    	rm -f $PIPE
    	mkfifo $PIPE || abort "cannot create FIFO $PIPE" 2
    	[ -x $DAEMON ] || abort "can't start daemon ($DAEMON)" 3
    	nohup $DAEMON >&- &
    	PID=$!
    	printf "%d\n" $PID >$PIDFILE
    	;;
      stop) [ -f $PIDFILE ] || 
    		abort "can't find daemon (already dead?)" 4
    	PID=$(cat $PIDFILE)
    	kill $PID || abort "couldn't kill daemon (pid $PID)" 5
    	;;
    esac
    exit 0
    
    
    #! /bin/sh
    # daemon script
    trap "rm -f $PIPE $PIDFILE" 0
    while true ;do 
        DATE=$(date)
        echo $DATE>$PIPE 
    done
    # exits only by signal
    


File translated from TEX by TTH, version 1.98.
On 7 Feb 2001, 18:52.