PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Shellscript, Netzwerkverbindung und Textfile



cPu
14.02.09, 15:12
Hallo.

Wir haben auf der Universität mehrere Schnittcomputer (mit Apple OS X). Wir wollen nun etwas Ordnung in die Sache bringen und so wurde ich beauftragt ein Skript zu schreiben. Da ich aber mit Shellskripts so gut wie keine Erfahrung habe muss ichs mir zwangsläufig selbst beibringen.

Aufgabenstellung ist folgende:

Beim Abmelden vom Rechner soll der Rechner in einen Defaultmode wiederhergestellt werden (das habe ich bereits, siehe unten). Dann kommt das wo ich mich nicht auskenne:

Es soll ein Netzlaufwerk geöffnet werden, dort liegt ein File mit kommaseparierten Werten.

Student;1234567
Student;1234568
Lektor;123456
Lektor;12343

Nun soll mein Skript auf der lokalen Festplatte kontrollieren, ob der Ordner Student existiert und ob darin ein Ordner mit dem Namen 1234567 angelegt ist. von diesem soll er die ordnergröße bestimmen und in ein anderes file mit ähnlicher struktur abspeichern. z.B für 500 byte schreibt er:

Student;1234567;500

wenn das getan ist, soll er wenn der ordner auf der lokalen festplatte nicht vorhanden ist diesen anlegen (die ordnergröße wird in folge dessen 0 byte sein). alle ordner welche nicht in diesem file stehen werden gelöscht! danach sollte die netzewerkverbindung wieder geschlossen werden und das skript sich beenden.

Mein Skript sieht zur Zeit wie folgt aus und funktioniert auch:

#!/bin/tcsh -f
#!/bin/sh

## Properties
set defGrp = staff

# This part is for debugging/testing purposes only
if ( $#argv < 1 ) then
echo "No user specified!"
exit 1
endif

# If this is the default user, replace the default home directory
# with a copy of the user template
if ( $1 == "student" ) then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
endif


Ich würde mich sehr freuen, wenn mir jemand Links zu Internetseiten geben könnte wo solche befehle beschrieben werden. Wie man z.B. aus einem File etwas ausliest und in ein anderes etwas reinschreibt. Oder wie man mit Netzwerkverbindugnen umgeht.

Natürlich am meisten würde es mich freuen, wenn sich jemand, der sich schon mit Skripts auskennt, mir bei meinem Vorhaben etwas unterstützt.

Vielen Dank und ich freue mich auf eure Kommentare,
cPu

Aqualung
14.02.09, 15:50
Es soll ein Netzlaufwerk geöffnet werden, dort liegt ein File mit kommaseparierten Werten.

nfs, samba?

http://www.tu-chemnitz.de/docs/lindocs/RH73/RH-DOCS/rhl-cg-de-7.3/s1-nfs-mount.html

http://www.swerdna.net.au/linhowtosambacifs.html

Auslesen einer Datei:



while read line; do
echo "$line"
done < file


Ex. ein Ordner?



if test -d /tmp; then
echo "/tmp exist".
fi

cPu
14.02.09, 17:05
Wow, vielen Dank für die hilfreiche Antwort! Es handelt sich um einen Samba-Share, sorry für die fehlende Info.

Ich denke, ich werde das Skript gleich hier online verfassen und würde euch bitten mir etwaige Fehler oder Verbesserungen gleich mitzuteilen. Das Skript will ich erst wenn es als "sicher" und "funktionierend" eingestuft ist auf einem Rechner in der Uni loslassen. Diese als auch der Sambaserver sind nämlich high priority und dürfen auf keinen Fall ausfallen.

Anbei meine rstes von mir verfasstes Shellskript *freude*. Da ist sicher manches falsch - aber aus Fehlern lernt man bekannterweise.
Leider fehlen noch Teile, welche ich erst ergooglen muss... vielleicht kann mich jemand dabei unterstützen und ein paar Tipps geben!

Sollte etwas falsch sein, so erbitte ich um Rückmeldung! Ich habe zurzeit das Passwort für den Server im plain-text im script, das tut aber nichts zur sache weil dieser account wird nur für leserechte am server benutzt und ist von den Studierenden bekannt.

Vielen vielen Dank für eure Unterstützung,
cPu


#!/bin/tcsh -f
#!/bin/sh

## Properties
set defGrp = staff

# This part is for debugging/testing purposes only
if ( $#argv < 1 ) then
echo "No user specified!"
exit 1
endif

# If this is the default user, replace the default home directory
# with a copy of the user template
if ( $1 == "student" ) then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
endif



#Open network connection
mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

studentnumber=0 #Matrikelnummer
dirsize=0 #Size of the directory

#Read the file
while read line; do

#Seperate line by Kommas
[??? Student;01234567]
[??? value;studentnumber]

value =
studentnumber =


#Check if directory does not already exist
if !test -d /home/$value/$studentnumber; then
mkdir /home/$value/$studentnumber
fi

#Read the directorysize
dirsize = du -s /home/$value/$studentnumber

#Look in the masterfile if there is already a line for this value and studentnumber and change the dirsize in an other file (/mnt/students/computer001_filesize)
[???]

#Look on the local drive if there is a directory which is not listed in the masterfile. If so, delete it.
[???]

done < /mnt/students/masterfile

#Close network connection
umount //[serverip]/students

Aqualung
14.02.09, 17:35
mypath=$(echo "$line" | sed "s/\;/\//")



dirsize=$(du -s "/home/$mypath")

L00NIX
15.02.09, 08:24
Nur zur Info, der OP verwendet eine Abart der CSH (tcsh), also Vorsicht, hier wurden schon Tipps/Syntax von Bourne-Shell bzw. bash gepostet.

Das Skript vom OP hat zwei She-Bangs, einer ist überflüssig und ich würde sagen der erste, denn wenn man Hilfe will, sollte man mit der Bourne Shell (oder kompatiblen, Linux: bash) programmieren.

Somit müssen alle if-Konstrukte aber umgebaut werden und set muss weg bei der Variablendeklaration und Vorsicht mit zuvielen Leerzeichen.

Ungetestet und unvollständig, also keine Garantie:


#!/bin/bash

## Properties
defGrp=staff

## files
master_file=/mnt/students/masterfile
size_file=/mnt/students/computer001_filesize

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# If this is the default user, replace the default home directory
# with a copy of the user template
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile existiert?
if [ ! -r "$master_file" ] ; then
echo "Kein Masterfile gefunden!"
exit 1
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# Datei wird unten ueberschrieben, alte Version behalten
/bin/mv "${size_file}" "${size_file}.old"

# Read the file
while read line ; do

# Seperate line by Kommas
# [??? Student;01234567]
# [??? value;studentnumber]

value=$( echo "$line" | cut -d; -f1 )
studentnumber=$( echo "$line" | cut -d; -f2 )


# Check if directory does not already exist
if [ ! -d /home/$value/$studentnumber ] ; then
/bin/mkdir -p /home/$value/$studentnumber
fi

# Read the directorysize
dirsize=$( du -s /home/$value/$studentnumber )

# Look in the masterfile if there is already a line for this value and studentnumber and change the dirsize in an other file (/mnt/students/computer001_filesize)
# => noe, einfach Datei neu anlegen
echo "$value;$studentnumber;dirsize" >> "$size_file"

# Look on the local drive if there is a directory which is not listed in the masterfile. If so, delete it.
# => Das wuerde ich in ein Extra-Skript auslagern...

done < "$masterfile"

# Close network connection
umount //[serverip]/students


Jedenfalls mal ne Basis, die sicher noch verbessert werden kann...

Gruß
L00NIX

cPu
15.02.09, 09:26
WOW!

Ich finde das echt klasse, dass mir hier so super geholfen wird! Echt vielen herzlichen Dank dafür, dass ihr euch die Zeit nehmt!

edit: Das Skript wird für Apple Os X programmiert! Funktioniert das dann auch mit dem angegebenen Shebang?

Okay, ich habe das Skript nun weiter bearbeitet. Der Pfad im Komma-sepparierten File ist etwas länger als ursprünglich von mir behauptet, das habe ich nun angepasst. Weiters soll der Hostname des Rechners dynamisch ausgelesen werden, wodurch ich das File auf jedem Rechner installieren kann. Ich ahsb im Script fett markiert. Wenns nicht stimmt, bitte unbedingt sagen! Der Ordner welcher gleich zu Beginn ersetzt wird, holt er sich nun auch vom Server, wenn der nicht verfügbar ist, nimmt er die lokale (etwaig veraltete) Version.

Offen ist nur noch der letzte Teil, der eigtnlich eigenständig ist. Ich würde das aber trotzdem gerne ins gleiche Script schreiben, weil diese Prozedur sollte gesammelt sein und nich in verschiedene Files ausgelagert werden. Das Skript wird dann beim herunterfahren des Rechners ausgeführt (nicht erst beim hochfahren, weil dann staret der Rechner schneller. Ziemlich schlau wie ich finde ;-) )

Gut. Der noch fehlende Teil sieht wie folgt aus:

Im Masterfile steht der Pfad in etwa so:
Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me

Den Vor- und Nachnamen kann ich vergessen, der wird für das Skript nicht gebraucht.

Das Script soll kontrollieren, ob auf der jeweiligen Verzeichnishöhe andere Ordner angelegt wurden, welche nicht im File stehen. Dies muss rekursiv erfolgen

Das heißt, es kontrolliert im Hauptordner, ob ein anderer Ordner hinzugefügt wurde. Wenn dieser Ordner keinem Studiengang entspricht, wir er gelöscht. Dann geht er ins erste Studiengangsverzeichnis. Wenn er einen Ordner finden der keinem Jahrgang entspricht, wird er gelöscht. Dann geht er in den ersten Jahrgang. Kontrolliert auf zuviele Matrikelnummern. Geht alle durch und startet mit dem nächsten Jahrgang. Geht wieder alle durch und geht in den nächsten Studiengang. usw.

Das ganze scheint mir so ziemlich kompliziert.

Vielleicht sollte man das anders anpacken und alles in ein temporäres file oder variable schreiben.

Man schreibt sich alle Ordner bis zur Höhe der Matrikelnummer raus und vergleicht dann das masterfile mit den erlaubten ordnern und dem temporären file. alles was zuviel ist wird gelöscht.

Das ganze ist aber schon sehr kompliziert und ich würde mich wirklich freuen, wenn sich jemand damit leichter tut als ich und mir wieder etwas helfen kann.

Vielen herzlichen Dank,
cPu




#!/bin/bash
#
# Coded by the community of www.linuxforen.de
# Special Thanks to: Aqualung, L00NIX
#

## Properties
defGrp=staff

## files
master_file=/mnt/students/masterfile
size_file=/mnt/students/$(echo hostname)_filesize

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile exists?
if [ ! -r "$master_file" ] ; then
echo "No Masterfile found! Using local home directory template"

if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
exit 1

else
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/mnt/students/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# File is going to be overwritten, backup old file
/bin/mv "${size_file}" "${size_file}.old"

# Read the file
while read line ; do

# Seperate line by Kommas
# [??? Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me]

studiengang=$( echo "$line" | cut -d; -f1 )
jahrgang=$( echo "$line" | cut -d; -f2 )
matrikelnummer=$( echo "$line" | cut -d; -f3 )
firstname=$( echo "$line" | cut -d; -f4 )
lastname=$( echo "$line" | cut -d; -f5 )


# Check if directory does not already exist
if [ ! -d /home/$studiengang/$jahrgang/$matrikelnummer ] ; then
/bin/mkdir -p /home/$studiengang/$jahrgang/$matrikelnummer
# kann man hier einbauen, dass er alle Ordner welche zuviel sind löscht?
fi

# Read the directorysize
dirsize=$( du -s /home/home/$studiengang/$jahrgang/$matrikelnummer )

# Look in the masterfile if there is already a line for this path and change the dirsize
echo "/home/$studiengang/$jahrgang/$matrikelnummer;dirsize" >> "$size_file"

# Look on the local drive if there is a directory which is not listed in the masterfile. If so, delete it.
# missing :-(

done < "$masterfile"

# Close network connection
umount //[serverip]/students

L00NIX
15.02.09, 10:41
OK, weiterer Versuch:


#!/bin/bash
#
# Coded by the community of www.linuxforen.de
# Special Thanks to: Aqualung, L00NIX
#

## Properties
defGrp=staff

## files
master_file=/mnt/students/masterfile
size_file=/mnt/students/$( /bin/hostname )_filesize # oder $( echo $HOSTNAME )
# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# ab hier haben wir ne temporaere Datei, die geloescht werden will, also
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile exists?
if [ ! -r "$master_file" ] ; then
echo "No Masterfile found! Using local home directory template"

if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
exit 1

else
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/mnt/students/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# File is going to be overwritten, backup old file
/bin/mv "${size_file}" "${size_file}.old"

# Read the file
while read line ; do

# Seperate line by Kommas
# [??? Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me]

studiengang=$( echo "$line" | cut -d; -f1 )
jahrgang=$( echo "$line" | cut -d; -f2 )
matrikelnummer=$( echo "$line" | cut -d; -f3 )
firstname=$( echo "$line" | cut -d; -f4 )
lastname=$( echo "$line" | cut -d; -f5 )


# Check if directory does not already exist
if [ ! -d /home/$studiengang/$jahrgang/$matrikelnummer ] ; then
/bin/mkdir -p /home/$studiengang/$jahrgang/$matrikelnummer
# kann man hier einbauen, dass er alle Ordner welche zuviel sind löscht?
# => nein
fi

# ...aber man kann ne Liste mit den exisitierenden Verzeichnissen erstellen
echo "/home/$studiengang/$jahrgang/$matrikelnummer" >> "$pattern_file"


# Read the directorysize
dirsize=$( du -s /home/$studiengang/$jahrgang/$matrikelnummer )

# Look in the masterfile if there is already a line for this path and change the dirsize
echo "/${studiengang}/${jahrgang}/${matrikelnummer}$" >> "$size_file"

done < "$masterfile"

# Look on the local drive if there is a directory which is not listed in the masterfile. If so, delete it.
cd /home
while read line ; do
echo "Verzeichnis nicht in Masterfile: '$line'"
done < $( /bin/find . -depth -mindepth 3 -type d | /bin/grep -v -f $"pattern_file" )

# Close network connection
umount //[serverip]/students



Der dir-delete-Teil sollte vor scharfschalten ausgiebig getestet werden, ob er auch die richtigen (!) Ergebnisse liefert. (Deswegen habe ich auch erstmal nur ein echo reingebaut)

Ich denke, es gibt eine bash unter MacOS X. Ob die in diesem Skript verwendeten Kommandos (z.B. mktemp) vorhanden sind, weiß ich aber nicht.


Gruß
L00NIX

Aqualung
15.02.09, 11:14
Weiters soll der Hostname des Rechners dynamisch ausgelesen werden


myhost=$(hostname -f)

oder einfach $HOSTNAME.
Oder:

uname -n

cPu
15.02.09, 11:22
Das ganze nimmt wirklich sehr gute Formen an! Danke L00nix, für deinen Einsatz!

Das letzte, was jetzt noch passieren sollte, bevor ich das ganze auf einem Testrechner mal ablaufen lasse ist, dass ich Ordner definiere, welche nicht gelöscht werden dürfen - aber auch nicht im masterfile stehen. Ich habe dazu meine Idee mal unten im Skript fett markiert (sie ist auch noch im kommentar, weil ichs erst nach dem Testlauf freischalte!)

Ich weiß nicht, ob ich eine Variable im Shellscript quasi als Feld definieren kann, bessert mich bitte aus, wenn ich falsch liege. Meine änderungen sind wieder fett formatiert. Weiters hab ich ein mv auf force gestellt, weil ich sonst vielleicht eine Fehlermeldung erhalte, welche mir sagt, dass das file bereits exisitert. (oder?)

Super! Ich werd mich nach den letzten Änderungen mal auf in die Uni machen und dass dann testen, lasse euch natürlich das Ergebnis wissen ;-)

Danke,
cPu


#!/bin/bash
#
# Coded by the community of www.linuxforen.de
# Special Thanks to: Aqualung, L00NIX
#

## Properties
defGrp=staff
savepath="/mnt/students/projects", "/mnt/students/irgendein-studiengang/irgendein-jahrgang/projects", "/mnt/students/irgendein-studiengang/projects", "/mnt/students/irgendein-studiengang/additionalprojects"

## files
master_file=/mnt/students/masterfile
size_file=/mnt/students/$( /bin/hostname )_filesize

# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# ab hier haben wir ne temporaere Datei, die geloescht werden will, also
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile exists?
if [ ! -r "$master_file" ] ; then
echo "No Masterfile found! Using local home directory template"

if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
exit 1

else
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/mnt/students/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# File is going to be overwritten, backup old file
/bin/mv -f "${size_file}" "${size_file}.old"

# Read the file
while read line ; do

# Seperate line by Kommas
# [??? Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me]

studiengang=$( echo "$line" | cut -d; -f1 )
jahrgang=$( echo "$line" | cut -d; -f2 )
matrikelnummer=$( echo "$line" | cut -d; -f3 )
firstname=$( echo "$line" | cut -d; -f4 )
lastname=$( echo "$line" | cut -d; -f5 )


# Check if directory does not already exist
if [ ! -d /home/$studiengang/$jahrgang/$matrikelnummer ] ; then
/bin/mkdir -p /home/$studiengang/$jahrgang/$matrikelnummer
fi

# Erstellen einer Liste mit den exisitierenden Verzeichnissen
echo "/home/$studiengang/$jahrgang/$matrikelnummer" >> "$pattern_file"


# Read the directorysize
dirsize=$( du -s /home/$studiengang/$jahrgang/$matrikelnummer )

# Look in the masterfile if there is already a line for this path and change the dirsize
echo "/${studiengang}/${jahrgang}/${matrikelnummer}$" >> "$size_file"

done < "$masterfile"

# Look on the local drive if there is a directory which is not listed in the masterfile. If so, delete it.

cd /home
while read line ; do
echo "Verzeichnis nicht in Masterfile: '$line'"
#
# if [ ! $savepath "$line" ] ; then
# rm -fr $line
# fi
#

done < $( /bin/find . -depth -mindepth 3 -type d | /bin/grep -v -f $"pattern_file" )

# Close network connection
umount //[serverip]/students

Aqualung
15.02.09, 11:26
Ich weiß nicht, ob ich eine Variable im Shellscript quasi als Feld definieren kann



myarr=("bla1 bla2" "bla3 bla4")
echo ${myarr[0]}
bla1 bla2
echo ${myarr[1]}
bla3 bla4

cPu
15.02.09, 11:30
Danke Aqualung für den Tipp!

Ich denke es sieht dann so aus:


savepath=("/mnt/students/projects" "/mnt/students/irgendein-studiengang/irgendein-jahrgang/projects" "/mnt/students/irgendein-studiengang/projects" "/mnt/students/irgendein-studiengang/additionalprojects")


Muss ich das in einer Zeile schrieben, oder kann ich das auch untereinand schrieben, damit es schöner aussieht und sich leichter verwalten lässt?


savepath=(
"/mnt/students/projects"
"/mnt/students/irgendein-studiengang/irgendein-jahrgang/projects"
"/mnt/students/irgendein-studiengang/projects"
"/mnt/students/irgendein-studiengang/additionalprojects"
)

L00NIX
15.02.09, 13:45
myhost=$(hostname -f)

Das könnte auf BSD-Systemen fatale Folgen haben, dann heißt der Host nämlich -f. Und da der MacOS X Kernel auf BSD basiert, warum nicht auch das eine oder andere Kommando, wie z.B. hostname?

Also ich wäre da vorsichtig!

Gruß
L00NIX

cPu
15.02.09, 14:12
Ich will den aktuellen Status des Codes nochmal veröffentlichen. Ich habe ein paar sachen geändert:


Das Script schreibt auch die Dirsize ins file :-)
Dieses dirfile wurde ebenfalls komma-seperated gestaltet.
Pfade habe ich auch etwas an die realität angepasst...
auch die verzeichnisse in savepath werden im sizefile gelistet


kann das mal jemand durchlesen und mir bestätigen, dass hier keine Syntaxfehler drinnen sind, weil dann kann ich das entgültig auf einem testrechner ausprobieren. ich bin mir noch unsicher, dass es auch die savepath-ordner in die filesize-datei schreibt. kann mich da jemand korrigieren?

Vielen Dank für all eure Unterstützung,
cPu


#!/bin/bash

## Properties
defGrp=staff

#The following will not be deleted
savepath=(
"/mnt/students/projects"
"/mnt/students/irgendein-studiengang/irgendein-jahrgang/projects"
"/mnt/students/irgendein-studiengang/projects"
"/mnt/students/irgendein-studiengang/additionalprojects"
)

## files
master_file=/mnt/students/mac-config
size_file=/mnt/students/mac-config/dirsize/$( /bin/hostname )

# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# delete the temporary file later
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile exists copy template user directory from server otherwise use local
if [ ! -r "$master_file" ] ; then
echo "No Masterfile found! Using local home directory template"
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
exit 1

else
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/mnt/students/mac-config/usertemplates/$( /bin/hostname )" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# File is going to be overwritten, backup old file
/bin/mv -f "${size_file}" "${size_file}.old"

# Read the masterfile
while read line ; do

# Seperate line by Kommas
# [??? Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me]

studiengang=$( echo "$line" | cut -d; -f1 )
jahrgang=$( echo "$line" | cut -d; -f2 )
matrikelnummer=$( echo "$line" | cut -d; -f3 )
firstname=$( echo "$line" | cut -d; -f4 )
lastname=$( echo "$line" | cut -d; -f5 )


# Check if directory does not already exist, create one if not
if [ ! -d /home/$studiengang/$jahrgang/$matrikelnummer ] ; then
/bin/mkdir -p /home/$studiengang/$jahrgang/$matrikelnummer
fi

# Create a list with all directories
#echo "/home/$studiengang/$jahrgang/$matrikelnummer" >> "$pattern_file"
#brauchen wir das noch, wenn wir eh alle ordnergrößen schreiben wollen?

# Read the directorysize
dirsize=$( du -s /home/$studiengang/$jahrgang/$matrikelnummer )

# Look in the masterfile if there is already a line for this path and change the dirsize
echo "${studiengang};${jahrgang};${matrikelnummer}$;${di rsize}" >> "$size_file"

done < "$masterfile"

# Look on the local drive if there is a directory which is not listed in the masterfile. If so, delete it.

cd /home
while read line ; do

# if [ ! $savepath "$line" ] ; then
echo "Verzeichnis wird geloescht: '$line'"
# rm -fr $line
# fi
#

done < $( /bin/find . -depth -mindepth 3 -type d | /bin/grep -v -f $"pattern_file" )

# Close network connection
umount //[serverip]/students

L00NIX
15.02.09, 14:33
Du weißt anscheinend nicht wirklich, was die Kommandos machen, wenn ich deine Kommentare lese...

Mal kurze Erläuterungen dazu:


#The following will not be deleted
savepath=(
"/mnt/students/projects"
"/mnt/students/irgendein-studiengang/irgendein-jahrgang/projects"
"/mnt/students/irgendein-studiengang/projects"
"/mnt/students/irgendein-studiengang/additionalprojects"
)

Was soll dieses Array bewirken? Wird nicht benutzt (bzw. ist auskommentiert).



## files
master_file=/mnt/students/mac-config
size_file=/mnt/students/mac-config/dirsize/$HOSTNAME


Die Variable zu nehmen ist vermutlich schneller und sicherer.



# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# delete the temporary file later
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15


Ist dir klar, was die beiden Zeilen machen?

Zuerst wird eine temporäre Datei mit generiertem Namen erzeugt und dieser Name in einer Varaible gespeichert.

Das trap-Kommando fängt Signale, die das Skript von Außen erhalten könnte ab, und führt den Teil zwischen den "" aus, also wird hier die Temporäre Datei gelöscht (aufräumen) und das Programm verlassen. Das passiert sowohl bei regulärem Beenden (Skriptende) oder auch bei den Signalen HUP, INT oder TERM.



# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi


Das ist nicht für's Debuggen, sondern für Info bei Fehlbedienung. Meiner Meinung nach sollte man solche Sicherungen immer in Skripte einbauen, d.h. ein Skript sollte beim Ausführen ohne Argumente nie einfach loslegen irgendwas zu tun. Aber das ist eine Konvention von mir.



# Create a list with all directories
#echo "/home/$studiengang/$jahrgang/$matrikelnummer" >> "$pattern_file"
#brauchen wir das noch, wenn wir eh alle ordnergrößen schreiben wollen?


Das echo schreibt Zeile für Zeile des oben definierten pattern_files, in dem alle vorhandenen Verzeichnisse aufgelistet sind. Klar brauchen wir das, schließlich wird daran entschieden, welche Verzeichnisse nachher nicht gelöscht werden.



cd /home
while read line ; do

# if [ ! $savepath "$line" ] ; then
echo "Verzeichnis wird geloescht: '$line'"
# rm -fr $line
# fi
#

done < $( /bin/find . -depth -mindepth 3 -type d | /bin/grep -v -f "$pattern_file" )


Das mit dem savepath kannst du dir schenken. Für den find manuell aus und versuche, den richtigen Wert für mindepth zu bekommen.

Das grep -v filtert dann alle Verzeichnisse raus, die in pattern_file stehen.

Folgendes gehört somit zusammen:



#!/bin/bash

# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# delete the temporary file later
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15

...

cd /home
while read line ; do
echo "Verzeichnis wird geloescht: '$line'"
done < $( /bin/find . -depth -mindepth 3 -type d | /bin/grep -v -f "$pattern_file" )


Ich würde übrigens Programme, von denen ich nicht weiß, was sie machen, nicht auf einem Produktivsystem ausführen.

Gruß
L00NIX

Aqualung
15.02.09, 14:38
Dein mount sollte _vor_ dem ersten Zugriff auf /mnt erfolgen.

cPu
15.02.09, 15:10
Danke L00nix für deine Erklärung. Natürlich weiß ich was das Script macht, so blind vertrauen tu ich dir auch nicht :p! Aber es kommen nun mal Befehle vor, welche ich noch nicht kannte (trap) und nur mal überblicksweise in die manpage geschaut habe, was das überhaupt macht. Aber im großen und ganzen weiß ich schon was hier passiert.

Aber Danke für die Warnung!

Aqualung: Auf mnt/students wird vorher noch nicht zugegriffen, da werden nur Variablen deklariert.

Zum Code. Ich wollte mit dem savepath ausdrücken, dass es vorkommt, dass für ein spezielles Projekt ein Ordner am Rechner verweilen darf.

Ich hab mir meine vorhin beschriebene Taktik nochmals überlegt und finde, dass es garnicht so schlau ist, diese im Script selbst zu definieren. Das würde erheblichen Aufwand bedeuten, wenn ich es updaten muss.

Stattdessen sollte es in einem seperaten file stehen (z.B. projects_file). Im "pattern_file" steht, was alles nicht gelöscht werden soll, kann ich dann einfach den Inhalt dieses Files um den des "projects" erweitern?

Ist es korrekt wenn ich das so formuliere?



projects_file=/mnt/students/mac-config/projects

while read line ; do
echo $line >> "$pattern_file"
done < "$projects_file"



Stimmt das dann auch noch mit dem Code später überein? Mir ist irgendwie noch der Verwendung von "-mindepth 3" unklar.


done < $( /bin/find . -depth -mindepth 3 -type d | /bin/grep -v -f "$pattern_file" )

Das ist das erste Shellscript das ich schreibe, ich hatte vorher noch nie wirklich was damit zu tun. Daher bitte ich um Nachsicht, wenn ich nach allem doppelt nachfrage. Ich will nur sichergehen, dass ich es mir nicht vielleicht falsch einlerne.

Auf alle Fälle vielen Dank für alles,
cPu

L00NIX
15.02.09, 15:20
Ich hab mir meine vorhin beschriebene Taktik nochmals überlegt und finde, dass es garnicht so schlau ist, diese im Script selbst zu definieren. Das würde erheblichen Aufwand bedeuten, wenn ich es updaten muss.

Stattdessen sollte es in einem seperaten file stehen (z.B. projects_file). Im "pattern_file" steht, was alles nicht gelöscht werden soll, kann ich dann einfach den Inhalt dieses Files um den des "projects" erweitern?


Ja, dann nimmt man eben eine include-Datei, die die Variablendeklarationen enthält:


...
config_file=/etc/mein_script.cfg

# Config Datei einlesen (sourcen)
[ -r "$config_file" ] && . "$config_file"
...




Stimmt das dann auch noch mit dem Code später überein? Mir ist irgendwie noch der Verwendung von "-mindepth 3" unklar.

Das ist das erste Shellscript das ich schreibe, ich hatte vorher noch nie wirklich was damit zu tun. Daher bitte ich um Nachsicht, wenn ich nach allem doppelt nachfrage. Ich will nur sichergehen, dass ich es mir nicht vielleicht falsch einlerne.


Für das erste Shell-Script ist das aber ein ganz schöner Brummer!

Zu mindepth:

Je nach Wert werden nur die gefundenen Verzeichnisse (-type d) ab dieser Tiefe angezeigt. Das hat den Grund, das du ja nicht die darüberliegenden Verzeichnisse in den Ergebnissen haben willst, denn die sollen ja nicht gelöscht werden.

Das "-depth" sorgt wiederum dafür, dass zuerst in die Verzeichnisse gewechselt wird und somit zuerst die allertiefsten Verzeichnisse angezeigt werden. Wenn ich es mir recht überlege, willst du anstelle von "-depth" ein "-maxdepth 3" haben, denn die darunterliegenden Verzeichnisssturkturen sind dir ja auch egal (werden ja mit gelöscht).

Experimentiere einfach mal mit find herum:


# find . -mindepth 3 -maxdepth 3 -type d


Gruß
L00NIX

cPu
15.02.09, 15:38
Ein weiteres lokales Config-File will ich vermeiden. Der weg über ein Projekte-File ist besser.


Ich werde den Einsatzzweck einmal erläutern, vielleicht wird dann klar, worauf ich mit dem Skript hinauswill.

Wir haben Apple Rechner auf dem jeder Student alle Rechte besitzt. Leider ist es nun so, dass jeder wild rumspeichert und sehr schnell die Platte voll ist und großes Chaos entsteht. Daher wollen wir Ordnung schaffen indem auf jedem Rechner eine Struktur zu finden ist wo jeder Student seinen Ordner hat, wo er Dinge abspeichern kann. Damit dieses fair-use Prinzip aber nicht schamlos ausgenutzt wird, wird der benutze Speicher in ein File geschrieben und mit einer anderen Software ausgelesen und analysiert (die ganz groben Fälle werden dann mit einer email benachrichtigt.)

Nun stelle ich mir vor, wir haben die Verzeichnisstruktur. diese ist wie bereits erwähnt:

Studiengang -> Jahrgang -> Matrikelnummer

Alles was in Matrikelnummer drinnensteht ist mir quasi egal. Da drinnen dürfen Ordner gemacht werden wie jeder will.

Wenn jemand einen Ordner in "Jahrgang" anlegt, also neben den ganzen Matrikelnummern ein zusätzlicher z.B. "Test" so sollte dieser gelöscht werden.
Das selbe gilt eine ebene höher: Ein Ordner in Studiengang, der nicht von mir festgelegt ist, wird gelöscht. Ganz darüber ein letztes mal wieder. Auf der Platte sind die Studiengänge und zusätzliche Ordner können zwar angelegt werden aber nach dem Neustart ist alles wieder gelöscht.

Bis zum "find" ist das Script wunderbar, ich habe mein file erstellt, mit verzeichnissen, welche nicht gelöscht werden dürfen ($pattern_file).

Nun muss ich aber irgendwie sagen, dass alles gelöscht wird, was nicht in diesem pattern_file steht.

Wenn, dann kommt nur ein "-maxdepth 3" in Frage, oder täusche ich mich da?

lg, cPu

L00NIX
15.02.09, 15:45
Also wenn du das Beschriebene erreichen willst, halte ich die Beschränkung der Benutzerrechte für einfacher und effektiver.

Bei dem find und pattern_file ging ich davon aus, dass nur auf der Matrikelnummer-Ebene gelöscht werden soll. Ich dachte, man will das "Ausscheiden" eines Studenten damit erfassen, so dass nur aktuell immatrikulierte Studenten ihre Verzeichnisse haben.

Wie auch immer... wenn du das wie gerade beschrieben haben willst, solltest du lieber die Benutzerrechte beschneiden.

Gruß
L00NIX

cPu
15.02.09, 15:49
nein, ich sag einmal nicht mehr dazu, als dass die Benutzerrechte so bleiben _müssen_ wie sie jetzt sind.

Dieser Lösungsweg stand in Frage, wurde dann aber wegen zahlreicher Gründe verworfen.

Es fehlt nur noch am letzten Schritt. wie ich zusätzliche Ordner lösche, welche nicht im Pattern_file sind und auf allen Ebenen gelöscht wird.

Danke und liebe Grüße,
cPu

L00NIX
15.02.09, 15:52
Füge manuell die nicht zu löschenden Verzeichnisse der Datei pattern_file hinzu und sorge mit mindepth und maxdepth für den richtigen zu suchenden Verzeichnisbereich.

Ich schätze mal, dass -mindepth 1 und -maxdepth 3 dir richtige Wahl wären...

cPu
15.02.09, 16:33
Anbei wiedereinmal der Code. Ich hab jetzt glaub ich das Projekteproblem gelöst, siehe Code.

Vielen wirklich herzlichsten Dank für deine Erklärungen und Hilfestellungen,
cPu



#!/bin/bash

## Properties
defGrp=staff

## files
master_file=/mnt/students/mac-config
size_file=/mnt/students/mac-config/dirsize/$( /bin/hostname )
project_file=/mnt/students/mac-config
projectsize_file=/mnt/students/mac-config/dirsize/$( /bin/hostname )_projects

# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# delete the temporary file later
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile exists copy template user directory from server otherwise use local
if [ ! -r "$master_file" ] ; then
echo "No Masterfile found! Using local home directory template"
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
exit 1

else
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/mnt/students/mac-config/usertemplates/$( /bin/hostname )" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# File is going to be overwritten, backup old file
/bin/mv -f "${size_file}" "${size_file}.old"

# Read the masterfile
while read line ; do

# Seperate line by Kommas
# [??? Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me]

studiengang=$( echo "$line" | cut -d; -f1 )
jahrgang=$( echo "$line" | cut -d; -f2 )
matrikelnummer=$( echo "$line" | cut -d; -f3 )
firstname=$( echo "$line" | cut -d; -f4 )
lastname=$( echo "$line" | cut -d; -f5 )


# Check if directory does not already exist, create one if not
if [ ! -d /home/$studiengang/$jahrgang/$matrikelnummer ] ; then
/bin/mkdir -p /home/$studiengang/$jahrgang/$matrikelnummer
fi

# Create a list with all valid directories
echo "/home/$studiengang/$jahrgang/$matrikelnummer" >> "$pattern_file"

done < "$masterfile"

#Read in the available Projects
while read line ; do
project=$(echo "$line")
done < "$projectfile"

# Look on the local drive if there is a directory which is not listed in the pattern_file. If so, delete it.

cd /home
while read line ; do
if [ ! $project "$line" ] ; then
echo "Verzeichnis wird geloescht: '$line'"
# rm -fr $line
fi
done < $( /bin/find . -mindepth 1 -maxdepth 3 -type d | /bin/grep -v -f $"pattern_file" )

# Read the directorysize
dirsize=$( du -s /home/$studiengang/$jahrgang/$matrikelnummer )
projectdirsize=$( du -s /home/projects/$project )

# Write the dirsize
echo "${studiengang};${jahrgang};${matrikelnummer};${dir size}" >> "$size_file"
echo "${project}" >> "$projectsize_file"

# Close network connection
umount //[serverip]/students

L00NIX
15.02.09, 16:49
Bisschen sinnloses Konstrukt:


#Read in the available Projects
while read line ; do
project=$(echo "$line")
done < "$projectfile"


Erstens steht in $line schon das, was du suchst, also würde


project=$line

ausreichen. Da ich aber vermute, du willst ein Array füllen, musst du


projects=( $( cat "$projectfile" ) )

benutzen und dann mit


echo ${projects[2]}

auf die Elemente (hier mit Index 2) darauf zugreifen.

Gruß
L00NIX

cPu
16.02.09, 01:43
Okay. Ja, ich will damit ein Array befüllen, damit ich alle Projekte in einer Variablen habe.

Die Klammern-Thematik ist mir noch etwas suspekt. Da werd ich mich wohl noch etwas einlesen müssen.

Ich hab mal den Code soweit, dass ich sage, von mir aus stimmt das und es funktioniert. Kannst du mal alles von oben nach unten durchlesen und checken, ob ich da Recht habe und es zum Testen kommen kann?

Danke,
cPu


#!/bin/bash

## Properties
defGrp=staff

## files
master_file=/mnt/students/mac-config/masterfile
size_file=/mnt/students/mac-config/dirsize/$( /bin/hostname )
project_file=/mnt/students/mac-config/projectfile
projectsize_file=/mnt/students/mac-config/dirsize/$( /bin/hostname )_projects

# Suchmuster (Negativliste)
pattern_file=$( /bin/mktemp /var/tmp/patterns-XXXXXX )

# delete the temporary file later
trap "/bin/rm -f $pattern_file ; exit 1" 0 1 2 15

# This part is for debugging/testing purposes only
if [ $# -eq 0 ] ; then then
echo "No user specified!"
exit 1
fi

# Open network connection
/bin/mount -t cifs -o username=[server_user],password=[server_password] //[serverip]/students /mnt/students

# Masterfile exists copy template user directory from server otherwise use local
if [ ! -r "$master_file" ] ; then
echo "No Masterfile found! Using local home directory template"
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/var/studentdummy/" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
exit 1

else
if [ $1 == "student" ] ; then
rm -rf /Users/$1
/usr/bin/ditto -rsrcFork "/mnt/students/mac-config/usertemplates/$( /bin/hostname )" /Users/$1
/usr/sbin/chown -R ${1}:${defGrp} /Users/$1
fi
fi

studentnumber=0 # Matrikelnummer
dirsize=0 # Size of the directory

# File is going to be overwritten, backup old file
/bin/mv -f "${size_file}" "${size_file}.old"

# Read the masterfile
while read line ; do

# Seperate line by Kommas
# [??? Studiengang;Jahrgang;Matrikelnummer;Vorname;Nachna me]

studiengang=$( echo "$line" | cut -d; -f1 )
jahrgang=$( echo "$line" | cut -d; -f2 )
matrikelnummer=$( echo "$line" | cut -d; -f3 )
firstname=$( echo "$line" | cut -d; -f4 )
lastname=$( echo "$line" | cut -d; -f5 )


# Check if directory does not already exist, create one if not
if [ ! -d /home/$studiengang/$jahrgang/$matrikelnummer ] ; then
/bin/mkdir -p /home/$studiengang/$jahrgang/$matrikelnummer
fi

# Create a list with all valid directories
echo "/home/$studiengang/$jahrgang/$matrikelnummer" >> "$pattern_file"

done < "$masterfile"

#Read in the available Projects
while read line ; do
project=( $( cat "$project_file" ) )
done < "$project_file"

# Look on the local drive if there is a directory which is not listed in the pattern_file. If so, delete it.

cd /home
while read line ; do
if [ ! $project "$line" ] ; then
echo "Verzeichnis wird geloescht: '$line'"
# rm -fr $line
fi
done < $( /bin/find . -mindepth 1 -maxdepth 3 -type d | /bin/grep -v -f $"pattern_file" )

# Read the directorysize
dirsize=$( du -s /home/$studiengang/$jahrgang/$matrikelnummer )
projectdirsize=$( du -s /home/projects/$project )

# Write the dirsize
echo "${studiengang};${jahrgang};${matrikelnummer};${dir size}" >> "$size_file"
echo "${project}" >> "$projectsize_file"

# Close network connection
umount //[serverip]/students

L00NIX
16.02.09, 15:17
Es fehlen nach wie vor die übergeordneten Verzeichnisse im pattern_file.

Füge sie manuell hinzu:


...
# Create a list with all valid directories
echo "^/home/$studiengang/$jahrgang/$matrikelnummer$" >> "$pattern_file"

# Erzeugt jede Menge Duplikate!
# Besser einmal vorher oder hinterher in separater Schleife alle gültigen Studiengänge und Jahrgänge in Liste aufnehmen!
echo "^/home/$studiengang/$jahrgang$" >> "$pattern_file"
echo "^/home/$studiengang$" >> "$pattern_file"

done < "$masterfile"

...


... und das ^ am Anfang und das $ am Ende ist Absicht, denn es ist ein Regulärer Ausdruck.

Gruß
L00NIX

cPu
16.02.09, 17:22
ok super.

ich werd das jetzt mal ausprobieren, ich hab mir heute schon einen testrechner zusammengebaut :-)

L00NIX, du bist mein Held und ich dir einen persönlichen Dank schuldig.
Danke für deine Unterstützung!
cPu