|
Weitere Beispiele
Die folgenden Beispiele stammen fast alle aus der täglichen Arbeit
und helfen bei der Administration eines Systems. Bei einigen Beispielen wurdensystemspezifische Teile des Originals weggelassen.Eingabe ohne RETURN-TasteSoll nur eine Taste zur Bestätigung gedrückt werden, z. B. 'j' oder 'n',läßt sich das mit dem read-Kommando nicht realisiert werden,da die Eingabe immer mit der Return-Taste abgeschlossen werden muß. Umeine Eingabe ohne Return zu realisieren sind zwei Dinge nötig:
- Schalten des Terminals auf ungepufferte Eingabe
- Einlesen der gewünschten Anzahl von Zeichen
Das Umschalten des Terminals wird mit stty raw erreicht. Für die
Eingabe wird das dd-Kommando (Disk Dump) zweckentfremdet. dd
liest von der Standardeingabe und schreibt auf die Standardausgabe. Für die
geplante Aktion werden die Parameter count (Anzahl zu lesender Blöcke)
und bs (Blocksize) verwendet. count enthält die Anzahl
der einzulesenden Zeichen, bs wird auf 1 gesetzt. Der entstehende
Programmteil sieht dann so aus:
echo "Alles Loeschen (j/n)\c"
stty raw -echo
INPUT=`dd count=1 bs=1 2> /dev/null`
stty -raw echo
echo $INPUT
case $INPUT in
j|J) echo "Jawoll" ;;
n|N) echo "Doch nicht" ;;
*) echo "Wat nu?" ;;
esac
Shell-Skript zum Eintragen eines neuen Benutzers
Dieses Skript soll nur zeigen, was beim Anlegen eines Benutzers alles
notwendig ist. Normalerweise exististieren bereits entsprechende Programme oder
Skripten (z. b. useradd oder das Administationstool YaST).
# Neuen Benutzer eintragen, Home-Directory erzeugen,
# .profile kopieren
PWDF=/etc/passwd
GRPF=/etc/group
STDPROF=.profile
if test $# -ne 3 ; then
echo "Usage: newuser Login-Name Gruppe Voller Name" ; exit 1
fi
NAME=$1 ; GRUPPE=$2
HOME=/home/$1
case $NAME in
?????????*) echo "Name ist zu lang" ; exit 1 ;;
*[A-Z]*) echo "Name enthaelt Grossbuchstaben" ; exit 1 ;;
esac
if grep "^$NAME:" $PWDF ; then
echo "Name schon vorhanden" ; exit 1
fi
UID=`tail -1 $PWDF | cut -f3 -d:`
UID=`expr $UID + 1`
if grep ".*:.*:$UID:" $PWDF ; then
echo "Passwortdatei ist nicht sortiert" : exit 1
fi
if grep ".*:.*:$GRUPPE:" $GRPF ; then
:
else
echo "Gruppen-Nummer nicht vorhanden" ; exit 1
fi
mkdir $HOME
cp $STDPROF $HOME
chown $UID $HOME $HOME/$STDPROF
chgrp $GRUPPE $HOME $HOME/$STDPROF
echo $NAME::$UID:$GRUPPE:$3:$HOME:/bin/sh >>$PWDF
echo $NAME::$UID:$GRUPPE:$3:$HOME:/bin/sh
Mit useradd geht das ganze viel einfacher, aber hier geht es ja um ein Beispiel.
Das folgende Skript vereinfacht die Anwendung von useradd, das relativ viele
Parameter besitzt.
#!/bin/sh
# Shell-Script zum Anlegen eines Benutzers
# Aufruf: newuser username gruppe Bemerkung
#
if [ $# != 3 ]; then
echo "Usage: `basename $0` username gruppe Bemerkung"
exit 2
fi
GRUP=$2
USR=$1
BEM=$3
GRP=/etc/group
PASS=/etc/passwd
SHAD=/etc/shadow
SKEL=/etc/skel
cp $PASS ${PASS}.bak
cp $SHAD ${SHAD}.bak
if [ "$USR" != "" ] ; then
echo "--- Anlegen User: $USR, Bemerkung: $BEM ---"
if `grep -s $GRUP $GRP >/dev/null` ; then
:
else
echo "--- Gruppe $GRUP unbekannt ---"
exit 2
fi
if `grep -s $USR $PASS` ; then
echo "+++ User existiert bereits +++"
exit 2
fi
/usr/sbin/useradd -d /home/${USR} -g $GRUP -s /bin/sh -c "$BEM" -m -k $SKEL $USR
if [ $? -eq 0 ] ; then
echo "+++ $USR angelegt +++"
else
echo "--- Fehler beim Anlegen von $USR ---"
fi
while [ -f /etc/ptmp ]; do
sleep 1
done
fi
echo "--- Fertig ---"
Löschen von Usern en bloc
Zum Löschen der User einer Schulungsgruppe wird anstelle des "Realname"
in der Datei /etc/passwd die Kursnummer eingetragen (z. B. "K1234"). Durch
das folgende Skript können durch Angabe eines Suchbegriffs die Teilnehmer
eines Jahrgangs komplett als User gelöscht werden. Das eigentliche Löschen
wird dabei von einen zweiten Skript übernommen.
# rm-all - Löschen User nach Stichwort in der Passwort-Datei
if [ $# -ne 1 ]; then
echo "Aufruf: $0 Suchbegriff"
exit 1
fi
# Erst mal testweise die Kandidaten fürs Löschen ausgeben
KANDIDATEN=`grep "$1" /etc/passwd | sed -e '1,$s/:.*//'`
echo "$KANDIDATEN loeschen (j/n)? \c"
read ANTWORT
if [$ANTWORT != "j" ]; then
echo "Abgebrochen!"
exit 1
fi
# jetzt wird wirklich gelöscht
/bin/rmuser $KANDIDATEN
Löschen von Usern
Das Skript "rmuser" ist etwas aufwendiger, da einige Sicherheitstest notwendig
sind. Auf den meisten Systemen gibt es ein Programm "userdel", das den
Benutzer aus /etc/passwd, /etc/group und /etc/shadow löscht. Bei anderen Anlagen
könnte man das Gleiche mit einem Skript erledigen. Das Löschprotokoll
wird per Mail an root geschickt.
# rmuser - löschen user
if [ $# -lt 1 ]; then
echo "Aufruf: $0 user [user ....]"
exit 1
fi
{
# Sicherheitskopien anlegen
cp /etc/passwd /etc/passwd.bak
cp /etc/shadow /etc/shadow.bak
# Jetzt wird es ernst
while [ $# -gt 0 ] ; do
USR=$1
N=`grep -c "$USR" /etc/passwd`
if [ $N -ne 1 ]; then
echo "$USR nicht vorhanden oder doppelt"
else
if [ `grep $USR /etc/passwd | cut -d: -f3` -lt 100 ]; then
echo "$USR hat eine ID kleiner 100, nicht geloescht"
else
echo "*** Loeschen User: $USER"
# Homedir aus /etc/passwd extrahieren
HOM=`grep $USR /etc/passwd | cut -f6 -d:`
rm -rf $HOM 2>&1
find / -user $USR -exec rm -f {} ";" 2>&1
/usr/sbin/userdel $USR
echo "--- $USR erledigt ..."
echo ""
fi
fi
shift
done
} | mailx -s "User-Loeschung" root
Man könnte das Skript noch um eine Prüfung auf weitere nicht zu löschende
User ergänzen. Außerdem sollte man das Ganze erst starten,
wenn sonst kein User mehr im System ist. Da das Skript bei vielen User recht lange
dauert, ist es am günstigsten, es als Batch im Hintergrund zu starten.
Staendig kontrollieren, wer sich ein- und ausloggt
#!/bin/sh
# PATH=/bin:/usr/bin
NEW=/tmp/WW1.WHO
OLD=/tmp/WW2.WHO
>$OLD # OLD neu anlegen
while : # Endlosschleife
do
who >$NEW
diff $OLD $NEW
mv $NEW $OLD
sleep 60
done
Speicherbelegung
Das Skript 'lsum' berechnet aus dem ls-Kommando den Gesamtspeicherplatz der ausgewählten
Dateien. Einfacher geht es aber mit 'du'.
#!/bin/sh
# Calculate the amount of space used by the specified files
# Default is the actual directory
SUM=0
TMPF=$HOME/$0$$
ls -l $* >$TMPF
while read D1 D2 D3 D4 D5 REST ; do # lesen aus TMPF
# Feld 5 enthaelt Groesse
SUM=`expr $SUM + 0$D5 / 1024`
done < $TMPF
echo "$SUM KBytes"
rm $TMPF
Preisfrage: Warum funktioniert folgende Variante nicht?
#!/bin/sh
SUM=0
ls -l | while read D1 D2 D3 D4 D5 REST ; do
SUM=`expr $SUM + 0$D5 / 1024`
done
echo "$SUM KBytes"
Optionen ermitteln
Oft ist es wünschenswert, wenn man bei Shellskripts auch Opionen angeben kann
(auf dieselbe Weise, wie bei Programmen). Die Optionen bestehen aus einem Buchstaben
mit dem '-' davor. Bei manchen Optionen folgt auch eine durch die Option spezifizierte
Angabe (z. B. beim 'pr'-Kommando der Header). Das folgende Fragment zeigt, wie
sich solche Optionen behandeln lassen. Die einzige Einschränkung besteht darin,
daß sich mehrere Optionen nicht zusammenziehen lassen ('-abc' statt '-a -b
-c' geht also nicht). Damit alle Optionen über eine Schleife abgehandelt werden
können, wird mit 'shift' gearbeitet. Wie üblich, können nach den Optionen
noch Dateinamen folgen. Ein Testaufruf könnte lauten:
otest -a -p "Parameter" -c *.txt
#!/bin/sh
# Bearbeiten von Optionen in Shellskripts
# Beispiel: -a -b -c als einfache Optionen
# -p <irgend ein Parameter> als "Spezial-Option"
READOPT=0
while [ $READOPT -eq 0 ] ; do # solange Optionen vorhanden
case $1 in
-a) echo "Option a"
shift ;;
-b) echo "Option b"
shift ;;
-c) echo "Option c"
shift ;;
-p) PARAM=$2 ; shift # Parameter lesen
echo "Option p: $PARAM"
shift ;;
*) if `echo $1 | grep -s '^-'` ; then # Parm. beginnt mit '-'
echo "unknown option $1"
shift
else
READOPT=1 # Ende Optionen, kein shift!
esac
done
echo "Restliche Parameter : $*"
'Rename'-Kommando
So mächtig das 'mv'-Kommando auch ist, es bietet keine Möglichkeit, eine
ganze Reihe von Dateien nach gleichem Schema umzubenennen (z. B. 'kap??.txt' -->
'kapitel??.txt'). Das folgende Skript leistet das gewünschte. Die ersten beiden
Parameter enthalten den ursprünglichen Namensteil (z. B. 'kap') und den neuen
Namensteil (z. B. 'kapitel'). Danach folgt die Angabe der zu bearbeitenden Dateien.
Wenn die Zieldatei schon existiert, wird nicht umbenannt, sondern eine Fehlermeldung
ausgegeben.
#!/bin/sh
# Alle Dateien umbennen, die durch $3 - $n spezifiziert werden
# dabei wird der String $1 im Dateinamen durch $2 ersetzt,
# wobei auch regulaere Ausdruecke erlaubt sind
if [ $# -lt 3 ] ; then
echo 'Usage: ren <old string> <new string> files'
echo 'Example: ren foo bar *.foo renames all files'
echo ' *.foo ---> *.bar'
exit 1
fi
S1=$1 ; shift
S2=$1 ; shift
while [ $# -gt 0 ]; do
for OLDF in $1 ; do
NEWF=`echo $OLDF | sed -e "s/${S1}/${S2}/"`
if [ -f $NEWF ] ; then
echo "$NEWF exists, $OLDF not renamed"
else
echo "renaming $OLDF to $NEWF"
mv $OLDF $NEWF
fi
done
shift
done
Löschen von Prozessen
Das Löschen eines Prozesses über die Prozeßnummer ist insofern lästig,
als man die Nummer meist erst per 'ps'-Kommando ermitteln muß. Das folgende
Skript erlaubt die Angabe eines beliebigen Strings (z. B. User- oder Programmname)
und löscht alle Prozesse, die diesen String in der Ausgabe des 'ps'-Kommandos
enthalten. Bei jedem Prozeß wird dann interaktiv gefragt, ob er gelöscht
werden soll. Vor dem eigentlichen Löschen wird noch einmal nachgesehen, ob
der Prozeß noch existiert, denn er könnte ja als Kindprozeß eines
vorher gelöschten Prozesses schon gekillt worden sein. Kleiner Schönheitsfehler:
Der zap-Prozess taucht auch in der Liste auf. Wie könnte man das beseitigen?
#!/bin/sh
# Loeschen Prozess durch Angabe eines Musters
TMPF=$HOME/zap..$$
if [ $# -lt 2 ]; then
echo "Usage: zap -Signal Muster"; exit 1
fi
SIG=$1
# alle Prozesse nach Stichwort durchsuchen
ps auwx | grep $2 | sed -e '1,$s/ */ /g' > $TMPF
while read X
do
set $X
echo "$X (j/n)? \c"
read ANTWORT </dev/tty
case $ANTWORT in
j*|J*) X=`ps auwx | grep -c $2`
if [ $X -ne 0 ]; then
kill $SIG $2
fi ;;
q*|Q*) break ;;
esac
done <$TMPF
rm $TMPF
Backup
Das folgende Skript zeigt, wie man den Backup eines Verzeichnisses automatisieren
kann. Normalerweise wird ein incrementeller Backup erzeugt, d. h. es werden nur
die Dateien gesichert, die nach dem letzten Backup geändert oder neu erstellt
wurden. Will man einen vollen Backup, muß man den Parameter '-a' (für
'all') angeben. Um festzustellen, welche Dateien neu sind, wird im entsprechenden
Verzeichnis eine leere Datei namens '.lastbackup' angelegt bzw. deren Zugriffsdatum
aktualisiert. Nach deren Änderungsdatum richtet sich die Auswahl der zu sichernden
Dateien. Beim allerersten Backup muß der Parmeter '-a' angegeben werden.
Die Angabe des Backup-Devices (/dev/tape) muß eventuell an die lokalen Gegebenheiten
angepaßt werden. Die Angabe '-depth' beim find-Kommando sorgt dafür,
daß die Dateien "von unten" her bearbeitet werden (nötig für
das cpio-Kommando).
#!/bin/sh
# Taeglicher Backup, als Parameter wird ein
# Verzeichnis angegeben
if [ $# -eq 0 ] ; then
echo "Aufruf: $0 [-a] <directory>"
echo "-a Alles sichern (sonst incrementell)"
exit
fi
echo "\nBand einlegen und [RETURN] druecken!"
read DUMMY
if [ "$1" = "-a" -o "$1" = "-A" ] ; then
if [ -d "$2" ] ; then
echo "Komplett-Backup von $2 ..."
MARKER=$2/.lastbackup
find $2 -depth -print | cpio -ovc >/dev/tape
touch $MARKER
echo "Fertig!"
else
echo "$2 ist kein Verzeichnis!"
exit
fi
else
if [ -d "$1" ] ; then
echo "Inkrementeller Backup von $1 ..."
MARKER=$1/.lastbackup
find $1 -newer $MARKER -print | cpio -ovc >/dev/tape
touch $MARKER
echo "Fertig!"
else
echo "$2 ist kein Verzeichnis!"
exit
fi
fi
echo "\nBand herausnehmen\n"
Zwischen-Backup
Manchmal ist es neben dm "normalen" Backup auf Band auch günstig,
einen weiteren Backup auf der Platte anzulegen - z. B. für den Fall,
daß jemand irrtümlich einen Datei löscht. Die kann dann
mit ein paar Tastenbetätigungen wieder hervorgezaubert werden. Das
folgende Skript sichert alle Dateien des WWW-Servers, die seit der letzten
Sicherung hinzugekommen sind. Als Zeitmarkierung dient das Datei-Zugriffsdatum
einer Datei namens ".lastcheck". Bei jedem Backup wird das Datum der Datei
per touch-Befehl aktualisiert. Man sieht auch schön, wie sich das
date-Kommando zum erzeugen von einzigartigen Dateinamen verwenden
läßt. Statt die Ausgabe zu unterdrücken, könnte
man sie auch per Mail an den WWW-Admin schicken (dann sollte tar etwas
auskunftsfreudiger gemacht werden).
#!/bin/sh
#
# Inkrementelles Sichern aller Dateien des WWW-Servers
#
{
TMPFILE="/tmp/check.$$"
TIMESTAMP="`date +%y%m%d`"
DIRECTORY="/home/httpd/htdocs"
WWWARCHIVE="/home/wwwarchive"
cd $DIRECTORY
find . -newer .lastcheck -print >$TMPFILE 2>/dev/null
touch .lastcheck
if [ `cat $TMPFILE | wc -l` -gt 0 ]
then
tar cf /$WWWARCHIVE/backup.$TIMESTAMP.tar $DIRECTORY
gzip /$WWWARCHIVE/backup.$TIMESTAMP.tar
chown wwwadm.staff /$WWWARCHIVE/backup.$TIMESTAMP.tar.gz
chmod 660 /$WWWARCHIVE/backup.$TIMESTAMP.tar.gz
fi
rm $TMPFILE
} > /dev/null 2>&1
eval-Anwendung
Endlich eine Anwendung für das eval-Kommando, auf die jeder schon gewartet
hat. Das folgenden Fragment zeigt, wie man in der Bourne-Shell die Ausgabe des
aktuellen Verzeichnisses im Prompt realisieren kann. Einziger Nachteil: Zum Logoff
muß man Ctrl-C und Ctrl-D drücken.
while true ; do
echo "`pwd`:$PS1\c"
read KDO
eval $KDO
done
Ausgaben aus cron- und at-Jobs auf ein Terminal
Wie schicke ich aus einem cron- oder at-Job etwas an den Benutzer, sofern er eingeloggt
ist? Das Problem liegt darin, daß der Job nicht wissen kann, an welchem Terminal
der User sitzt. Also muß zunächst per 'who'-Kommando festgestellt werden,
ob der Adressat eingeloggt ist und an welchem Terminal er sitzt. Dann kann eine
Nachricht nach folgendem Schema an den User geschickt werden.
#!/bin/sh
# Nachricht ($2-$nn) an User ($1) senden, sofern dieser eingeloggt ist
NAM="$1"
shift
MSG="$@"
if who | grep -q $NAM ; then # User eingeloggt?
write $NAM < $MSG
fi
Rundruf
Nach dem gleichen Schema kann man ein "wall für Arme" realisieren.
Es werden jedoch im Gegensatz zum "echten" 'wall' nur die Benutzer erreicht,
die Ihren Mitteilungsempfang offen haben.
who | while read USR REST ; do # für alle aktiven User
banner"Teatime!" | write $USR
done
Das "bang"-Skript
Manche Kommandos möchten einen Dateinamen als Argument und nicht die Daten
über die Standardeingabe haben. Für solche Kommandos muß man öfter
eine temporäre Datei anlegen, die nach dem Kommandoaufruf wieder gelöscht
wird. Ein typisches Beispiel dafür ist ein Vergleich zweier Dateien. Das Kommando
"comm" benötigt die Namen der beiden Dateien. Wenn die Dateien vor
dem Vergleich sortiert werden müssen, sieht der konventionelle Ansatz
folgendermaßen aus:
sort file1 >/tmp/file1.sor
sort file2 >/tmp/file2.sor
comm /tmp/file1.sor /tmp/file2.sor
tmp/file[12].sor
Das folgende Skript namens "!" führt ein Kommando aus, das als Parameter
übergeben wird, und liefert den Namen einer temporären Datei zurück,
in dem das Ergebnis der Kommandoausführung gespeichert wurde. Das wäre
aber noch kein Fortschritt. Der Trick ist, daß die temporäre Datei nach
fünf Minuten automatisch gelöscht wird. Unsere Aufgabe läßt sich
dann als Einzeiler schreiben:
comm `! sort file1` `! sort file2`
Die Schwierigkeit beim Schreiben von "!" liegt darin, daß die aufrufende
Shell ("comm"-Kommando) normalerweise wartet, bis das aufgerufene Skript
("! sort ...") terminiert - aber dieses soll ja fünf Minuten warten
und dann die Datei löschen. In diesem Fall wäre aber die temporäre
Datei schon wieder leer. Die Lösung zeigt die Auflistung von "!":
#!/bin/sh
# Kommado ausführen,
# Ergebnis in temp. Datei,
# Dateiname zurückgeben
TEMPDIR=/tmp
TEMPF=$TEMPDIR/BANG..$$
# Trap zum Löschen von TEMPF
trap 'rm -f $TEMPF; exit' 1 2 15
# Falls kein Kommando, nur Dateinamen liefern
if [ $# -eq 0 ] ; then
echo "Usage: `basename $0` command [args]" 1>&2
echo $TEMPF
exit 1
fi
# Kommando ausführen, Dateiname liefern
"$@" > $TEMPF
echo $TEMPF
# jetzt kommt der Trick:
exec >&- # Standardausgabe schließen, rufende Shell wartet nicht!
( sleep 300 ; rm -f $TEMPF ) & # Löschauftrag --> Hintergrund
exit 0
Rekursives Suchen in Dateien
#!/bin/sh
# Rekursives Skript zum Suchen und Ersetzen von Text-Pattern
#
PROGNAME=`basename $0`
TEMPDAT=/tmp/`basename $0.$$`
if test $# -lt 4; then
echo "$PROGNAME : Recursive search-and-replace-skript."
echo "usage : $PROGNAME <start-dir> <file-expression> \
<search-pattern> <replace-pattern>"
echo "example : $PROGNAME . \"*.html\" \"abc\" \"xxx\" "
echo "Both patterns use ex/vi-syntax !"
else
find $1 -type f -name "$2" -print > $TEMPDAT
for NAME in `cat $TEMPDAT`
do
echo -n "Processing $NAME.."
ex $NAME << EOT > /dev/null
1,\$ s/$3/$4/g
wq
EOT
echo "done."
done
rm $TEMPDAT
fi
Datei mit Verzeichnisinfo anlegen
Bei FTP-Servern ist es üblich, eine Datei mit einen Verzeichnislisting in
den einzelnen Download-Verzeichnissen anzulegen. Interessenten können sich
erst einmal diese Datei holen und in Ruhe durchsehen. Das folgende Skript
erzeugt zwei VArianten: 'ls-lR' mit der Verzeichnisinfo und dieselbe Datei
gepackt ('ls-lR.Z').
#!/bin/sh
# Generieren ls-Rl und ls-RL.Z
# Eingabeparameter: Ausgangsverzeichnis
#
if [ $# -ne 1 ]; then
echo "Aufruf: `basename $0` Verzeichnis"
exit 1
fi
ROOT=$1
LSFILE=$ROOT/ls-lR
TMPFILE=/tmp/mkls.$$
cd $ROOT
echo "$ROOT" > $TMPFILE
# Verzeichnisinfo erstellen, Leerzeilen und Summenangabe raus
ls -lR 2>/dev/null | grep -v "^total" | grep -v "^$" >> $TMPFILE
cp $TMPFILE $LSFILE
cat $LSFILE | compress -f > $TMPFILE
cp $TMPFILE ${LSFILE}.Z
rm $TMPFILE
Ständig wachsende Dateien kürzen
Viele Logfiles wachsen notorisch. Wenn man nicht achtgibt, ist irgendwann
die Platte voll. Über ein per crontab regelmäßig aufgerufenes
Skript kann man die Dateien klein halten. Nebenbei kann man auch gleich
die spezielle Logdatei wtmp mit bearbeiten. Die Datei '/etc/prune_list'
enthält die zu überwachenden Dateien in der Form 'dateiname länge'.
Für jede Datei existiert eine Zeile, wobei der Dateiname mit vollem
Pfad angegeben werden muß.
Schließlich löscht das Skript noch alle Dateien aus dem /tmp-Verzeichnis,
auf die seit 8 Tagen nicht mehr zugegriffen wurde und auf der gesmaten Platte
alle Dateien mit den Namen 'a.out', 'core' und '*.o' die 8 Tage alt oder älter
sind.
#!/bin/sh
#
# prune: Shorten textfiles listetd in $FLIST.
# files are shortened to a certain number of lines at
# their end. In $FLIST are lines containing filename
# (full path) and number of remaining lines. E. g.:
# /var/adm/messages 500
# /var/adm/debug 100
#
# /var/adm/wtmp will also be shortened
# a.out, core, *.o and tmp-files will be deleted after 8 days
#
HOSTNAME=/bin/hostname # Pfad hostname-Programm
FLIST=/etc/prune_list # Liste zu loeschender Dateien
TMPF=/tmp/prune.$$ # Temporaerdatei
{
while read FILE LEN
do
if [ -n $FILE -a -n $LEN ] ; then
if [ `wc -l $FILE` -lt $LEN ] ; then
echo "prune: ${FILE} nothing to do"
else
tail -$LEN $FILE >$TMPF
cp $TMPF $FILE
echo "prune: ${FILE} shortened to $LEN lines"
fi
else
echo "prune: error in $FLIST, FILE or LEN missing"
fi
done < $FLIST
rm $TMPF
cd /var/adm
[ -f wtmp.3 ] && cp wtmp.3 wtmp.4
[ -f wtmp.2 ] && cp wtmp.2 wtmp.3
[ -f wtmp.1 ] && cp wtmp.1 wtmp.2
cp wtmp wtmp.1
cp /dev/null wtmp
chmod 664 wtmp
echo "wtmp shortened"
[ -f wtmpx.3 ] && cp wtmpx.3 wtmpx.4
[ -f wtmpx.2 ] && cp wtmpx.2 wtmpx.3
[ -f wtmpx.1 ] && cp wtmpx.1 wtmpx.2
cp wtmpx wtmpx.1
cp /dev/null wtmpx
chmod 664 wtmpx
echo "wtmpx shortened"
# clean up /tmp and /usr/tmp
/usr/bin/find /tmp -type f -atime +7 -exec /bin/rm -f {} \;
/usr/bin/find /var/tmp -type f -atime +7 -exec /bin/rm -f {} \;
/usr/bin/find /usr/tmp -type f -atime +7 -exec /bin/rm -f {} \;
/usr/bin/find / \( -name a.out -name core -name '*.o' \) -atime +7 \
-exec /bin/rm -f {} \;
} | mailx -s "Output from PRUNE `$HOSTNAME`" root 2>&1
Kleiner Sicherheitscheck
Im Lauf der Zeit "verlottert" jedes System ein wenig. Es gibt noch Dateien von
längst gelöschten Usern, manche User haben kein Passwort und dergleichen
mehr. Ein paar Sicherheitschecks macht das folgende Skript, das man nach den
eigenen Bedürfnissen erweitern kann.
#!/bin/sh
# Programm to run weekly to check some important items
# must be run by root
#
# find accounts without password
echo ""
echo "Accounts without password"
echo "-------------------------"
/usr/bin/grep '^[^:]*::' /etc/passwd
# find accounts with UID 0 and/or GID 0
echo ""
echo "Accounts with ID 0"
echo "------------------"
/usr/bin/grep ':00*:' /etc/passwd
# Check Permissions
echo ""
echo "Permissions of important files"
echo "------------------------------"
ls -l /etc/passwd /etc/group /etc/hosts /etc/host.equiv /etc/inetd.conf
echo ""
echo "SUID-files"
echo "-----------"
/usr/bin/find / -perm -4000 -type f -exec ls -l {} \;
echo ""
echo "SGID-files"
echo "----------"
/usr/bin/find / -perm -2000 -type f -exec ls -l {} \;
echo ""
echo "World-writable files"
echo "--------------------"
/usr/bin/find / -perm -2 \( -type f -o -type d \) -exec ls -l {} \;
echo ""
echo "Files without owner"
echo "-------------------"
/usr/bin/find / -nouser -exec ls -l {} \;
echo ""
echo "/var/adm/sulog:"
echo "---------------"
cat /var/adm/sulog
} 2>&1 | mailx -s "Check-Output" root 2>&1
Pack-Automat
Meine Seminarunterlagen auf dem Webserver ändern sich recht oft. Weil ich
immer vergesse, auch eine gepackte Version des gesamten Verzeichnisses mit
alle Bildern und HTML-Dateien zu erzeugen, läft per cron-Auftrag jede Nacht
der Automatik-Packer. Als Merker dienen zwei Dateien, .lastpack,
die sich im übergeordneten Verzeichnis befindet und angibt, wann zuletzt
gepackt wurde. Gibt es im Verzeichnisbaum darunter keine Dateien, die neuer
sind als .lastpack, wird nichts gemacht. In jedem darunterliegenden
Verzeichnis gibt es eine Datei .lastupd, die es erlaubt, für das
jeweilige Verzeichnis festzustellen, ob neue Dateien vorliegen. Ist das der Fall,
wird das Packen gestartet. Das Ergebnis der Gesamtoperation wird per E-Mail an
den Webmaster geschickt:
#!/bin/sh
#
# Erzeugt im WWW-Verzeichnis der Skripten
# jeweils gepackte Versionen.
# Die Dateien heissen <Verzeichnisname>.tar.gz
#
cd /home/httpd/lbs/skripten
[ `find . -newer ".lastpack" -print | wc -l` -eq 0 ] && exit
{
ls > ptmp.$$
while read DIR
do
if [ -d $DIR ] ; then
NAME=`basename $DIR`
cd $NAME
if [ -f .lastupd ] ; then
if [ `find . -newer ".lastupd" -print | wc -l` -gt 0 ] ; then
rm $NAME.tgz
/root/bin/upd-index-html
tar cf $NAME.tar *
gzip -f $NAME.tar
mv $NAME.tar.gz $NAME.tgz
touch .lastupd
echo "$NAME ... DONE!"
else
echo "$NAME ... nothing to do"
fi
else
touch .lastupd
fi
cd ..
fi
done < ptmp.$$
rm ptmp.$$
touch /home/httpd/lbs/skripten/.lastpack
} | mailx -s "Skripten-Packer" webmaster
|
|
|