Mit den passenden Befehlen werten Sie Informationen über Dateien und Verzeichnisse so aus, dass diese beim Organisieren und Verarbeiten helfen.
In einem Verzeichnis liegen Hunderte oder sogar Tausende Dateien, und Sie möchten Ordnung schaffen. Dabei zeigt sich: Die Dateinamen haben keine einheitliche Endung; ein Kopieren nach dem Muster cp *.txt klappt also nicht. In einem anderen Szenario steht das Datum des letzten Zugriffs im Mittelpunkt – wichtig beim Sichern, in der Forensik sowie beim Verwalten von Versionen.
Anstelle langwieriger Klicks im grafischen Dateimanager hilft ein Shell-Skript mit dem Test-Befehl, wenn es um das Erkennen von Objekten im Dateisystem geht, und der Frage, welche Informationen die Daten darüber hinaus noch hergeben.
Typ bestimmen
Mittels des Befehls file erhalten Sie Informationen über den Inhalt einer Datei. Zusammen mit der Option -i erhalten Sie eine Ausgabe wie in Abbildung 1 gezeigt. Bei der untersuchten Datei handelt es sich um reinen Text. Dateiendungen führen File dabei nicht in die Irre, es kommt auf den Inhalt an (Abbildung 2).
Abbildung 1: Der Befehl file greift beim Erkennen von Inhalten auf eine Liste charakteristischer Muster zurück.
Abbildung 2: Dank der Tests auf die Muster im Inhalt bestimmt File selbst solche Dateien zuverlässig, deren Endungen nicht dem tatsächlichen Inhalt entsprechen.
Das Tool bezieht seine Musterinformationen aus dem Magic-File /usr/share/misc/magic.mgc. Für Spezialfälle erstellen Sie bei Bedarf eine eigene Magic-Datei und übergeben sie File beim Aufruf mit der Option -m Datei. Interessiert Sie speziell der MIME-Typ einer Datei, verwenden Sie die Option --mime-type.
Mit File greifen Sie selbst auf Gerätedateien zu (Abbildung 3) und werten diese aus. Dabei gibt die Software zusätzlich die Major- und Minor-Nummern aus (Abbildung 3). Mit entsprechenden Rechten erhalten Sie Angaben zum Dateisystem (Abbildung 4). Dazu verwenden Sie die Option -s Gerätedatei. Geben Sie hier nur das Gerät für die Festplatte ohne die Nummer für die Partition an, erhalten Sie Angaben unter anderem zur Blockgröße.
Abbildung 3: Rufen Sie die Informationen für eine Gerätedatei auf, zeigt das Tool File wenn möglich Major- und Minor-Nummer.
Abbildung 4: Da Geräte unter Linux sich wie eine Datei verhalten, liefert File zu diesen ebenfalls Informationen.
TIPP
Die Major-Nummer gibt dem Kernel den Treiber für das Gerät an. Die Minor-Nummer hilft dem Treiber, mehrere von ihm verwaltete Geräte zu unterscheiden.
File gibt die Informationen in der Regel in der Form Dateiname: Daten aus. Diesen Umstand machen Sie sich bei Bedarf beim Einsatz in Shell-Skripten zunutze. Verwenden Sie im Skript eine For-Schleife, brauchen Sie eindeutige Dateinamen. Die erhalten Sie durch ls -1. Je Zeile ergibt dies einen Dateinamen. Die Subshell im Schleifenkopf der For-Schleife liefert damit zuverlässige Argumente, solange sich kein Leerzeichen im Dateinamen befindet. Hier müssten Sie vorher den Namen umwandeln oder Anführungszeichen verwenden.
Das Beispiel in Listing 1 zeigt eine Anwendung, die gezielt PDF-Dateien sucht und zur Auswahl anbietet (Abbildung 5). Das dynamische Auswahlmenü entsteht dabei unter Zuhilfenahme von Smenu.
Listing 1
#! /bin/bash
# Vorbelegung Menueausstieg
menu="E-N-D-E"
cd $HOME/Daten
# PDF-Dateien suchen
for i in $(ls -1); do
file $i | cut -d \: -f2 | grep -q PDF
if [ $? -eq 0 ]; then
# Auswahl montieren
menu=$(echo $menu $i)
fi
done
# Auswahlmenue mit Smenu und PDF-Anzeige
while true; do
ausw=$(echo $menu | smenu -n 10 -t1 )
if [ "$ausw" = "E-N-D-E" ]; then
exit
fi
atril $ausw
clear
done

Abbildung 5: Mit nur wenigen Zeilen Shellcode sowie dem Tool Smenu erstellen Sie eine einfache Auswahl für einen bestimmten Typ von Dateien.
Statusinformationen
Zu den mit dem Befehl stat auslesbaren Informationen über Dateien und Verzeichnisse gehört mehr oder weniger alles, was Sie auch mit Ls erhalten. Ohne Angabe einer weiteren Option erhalten Sie alle Daten über eine Datei aufgelistet. Abbildung 6 stellt auch gleich die Auswirkung eines Lesezugriffs dar. Beachten Sie hierbei die Zeile Zugriff mit den Datum- und Uhrzeitangaben. Allerdings funktioniert genau dies nicht bei mit der Option noatime eingehängten Dateisystemen. Damit wird der Datenzugriff beschleunigt, weil das Dateisystem nicht bei jedem Lesezugriff einen Eintrag vornehmen muss.
Mittels stat -c Format lesen Sie gezielt einzelne Informationen über eine Datei (oder ein Dateisystem) aus und werten diese in einem Skript aus. Die Tabelle “Stat-Formatangaben” führt die wichtigsten Möglichkeiten auf. Abbildung 7 zeigt einige Aufrufe, unter anderem die Abfrage der Zugriffsrechte in numerischer Form. Diese Information eignet sich unter Umständen für ein Installationsskript.
|
Anweisung |
Angabe |
|---|---|
|
|
Zugriffsrechte in numerischer Form |
|
|
Zugriffsrechte in ausführlicher Form |
|
|
Gerätenummer (dezimal) für Gerätedatei |
|
|
Major-Nummer Gerätedatei (Hexadezimal) |
|
|
Minor-Nummer Gerätedatei (Hexadezimal) |
|
|
Dateityp |
|
|
Dateisystem, in dem sich die Datei befindet |
|
|
UID des Besitzers |
|
|
Benutzername des Besitzers |
|
|
GID |
|
|
Gruppenname |
|
|
letzter Lesezugriff (Klartext) |
|
|
letzter Lesezugriff (Unix-Sekunden) |
|
|
letzte Änderung (Klartext) |
|
|
letzte Änderung (Unix-Sekunden) |
|
|
letzter Zugriff (Klartext) |
|
|
letzter Zugriff (Unix-Sekunden) |
Beachten Sie dabei, dass die deutschsprachige Ausgabe von Stat stellenweise etwas mehrdeutig ausfällt: So meint etwa Zugriff den letzten lesenden Zugriff, wobei Sie aber beachten sollten, dass Mount-Optionen wie noatime diesen Wert beeinflussen. Der Begriff Modifiziert bezieht sich auf den Inhalt der Datei, enthält also unter Umständen das Erstellungsdatum, immer aber den letzten Schreibzugriff. Bei Geändert sehen Sie Angaben zum Ändern der Zugriffsrechte, des Eigentümers oder Ähnliches. Den Wert für Geburt ermittelt Stat unter Linux derzeit wegen eines Programmfehlers nicht.
Listing 2 zeigt ein kleines Skript, das die Zugriffsrechte einer Datei ausliest und anschließend ändert, falls sie zu lax ausfallen. Es ruft das Kommando zum Ändern der Rechte mit der Option -v auf, sodass Sie im Terminal sehen, was es tut. Abbildung 8 zeigt die Datenbasis dazu, Abbildung 9 den Durchlauf des Skripts.
Listing 2
#! /bin/bash
# $1 als Verzeichnis setzen,
# sonst Abbruch
if [ -z $1 ]; then
exit
fi
# Wechsle ins Verzeichnis
cd $1
for i in $(ls -1); do
# Zugriffsrechte auswerten
stat -c %a $i | grep -q 75
if [ $? -eq 0 ]; then
# Aendern, wenn Gruppe
# oder Rest die Datei
# ausfuehren duerften.
chmod -v 700 $i
fi
done

Abbildung 8: Zu lax gesetzte Rechte auf Dateien gewähren Unbefugten unter Umständen Einblick in die Daten.
Abbildung 9: Der Ablauf des Shell-Skripts aus Listing 2 und die Anzeige der geänderten Dateien.
Zeitstempel ändern
Normalerweise modifizieren Anwendungen, die mit der betroffenen Datei arbeiten, die Informationen in den Zeitstempeln. Von Hand gelingt das mit dem Kommando touch (siehe Tabelle “Touch-Optionen”). Wenn Sie Touch mit einem nicht existierenden Dateinamen ausführen, legt das System einen entsprechenden Eintrag ins Dateisystem vor, legt also eine Datei ohne Inhalt an. Rufen Sie touch Datei ohne Optionen auf, dann aktualisiert das Programm alle Zeitstempel der Datei auf die Systemzeit.
|
Option |
Aktion |
|---|---|
|
|
Zugriffszeit ändern |
|
|
Modifikationszeit ändern |
|
|
Zeit statt Systemzeit verwenden |
|
|
Angabe einer Referenzdatei, von der Touch die Zeitstempel übernimmt |
Die Zeitangabe für die Option -t erfolgt in der Form MMTThhmm. Sie dürfen die Angabe zusätzlich um das Kalenderjahr und die Sekunden erweitern: JJMMTThhmm.ss. Abbildung 10 zeigt das Ändern der Zugriffszeit mithilfe von Touch. In Abbildung 11 sehen Sie ein Beispiel für das Referenzieren über eine bestehende Datei. Sie erkennen in der folgenden Ausgabe des Kommandos stat das besondere Datum für den Zugriff, das der Befehl in Abbildung 10 gesetzt hat.
Dateien testen
Das Test-Kommando kommt meist nicht ausgeschrieben zum Einsatz, sondern in der Notation mit eckigen Klammern und entsprechenden Optionen (Listing 3). Es dient zum Auswerten der Art und der Zeitstempel von Objekten im Verzeichnisbaum. Dabei liefert es einen Rückgabewert von 0, wenn die getestete Kondition zutrifft (“wahr”). Die Tabelle “Test-Optionen” listet einige Möglichkeiten auf.
Listing 3
if [ $? -eq 0 ]; # ist dasselbe wie if test $? -eq 0;
|
Test |
wahr, wenn … |
|---|---|
|
|
Objekt existiert |
|
wahr, falls das Objekt existiert und … |
|
|
|
eine Blockgerätedatei ist |
|
|
eine Zeichengerätedatei ist |
|
|
ein Verzeichnis ist |
|
|
eine gewöhnliche Datei ist |
|
|
das Gruppen-ID-Bit gesetzt ist |
|
|
der Gruppeneintrag von Prozess und Datei übereinstimmen |
|
|
ein symbolischer Link ist |
|
|
das Sticky-Bit gesetzt ist |
|
|
ein symbolischer Link ist |
|
|
der Abfrageprozess denselben Eigentümer aufweist |
|
|
ein FIFO ist |
|
|
lesbar ist |
|
|
dessen Größe nicht 0 ist |
|
|
ein Socket ist |
|
|
das UID-Bit gesetzt ist |
|
|
schreibbar ist |
|
|
ausführbar ist |
|
wahr, wenn Objekt1 existiert und … |
|
|
|
Objekt2 sich auf dasselbe Objekt bezieht |
|
|
neuer als Objekt2 ist |
|
|
älter als Objekt2 ist |
Der Befehl test bietet sich etwa an, um in einem If-Konstrukt eine Unterscheidung zu treffen. Der Einsatzbereich fällt dabei umfangreich aus. In einem Skript zum Sichern von Daten wäre es beispielsweise möglich, zu prüfen, ob die Datei DASI.INFO existiert. Falls ja, erstellt das Skript eine Kopie von allen Dateien, die neuer als der Zeitstempel dieser Datei sind. Anderenfalls nimmt das Skript eine Komplettsicherung vor.
Listing 4 zeigt den Code für ein Skript, das ein Verzeichnis namens DASITEST anlegt, falls es nicht existiert – eine alltägliche Angelegenheit, die Sie auf diese Weise schnell erledigen (Abbildung 12).
Listing 4
#! /bin/bash
uvzneu () {
# DATEI?
if [ -f DASITEST ]; then
read -p "Datei mit gleichem Namen vorhanden! Umbenennen (j)? " we
if [ "$we" = "j" ]; then
mv DASITEST DASITEST.datei
else
echo "Die Datei DASITEST entweder löschen oder verschieben!"
echo "SKRIPTENDE"
fi
fi
if [ -d DASITEST ]; then
cd DASITEST
echo -n "Ich befinde mich im Verzeichnis $PWD"
echo " "
else
echo "Anlegen DASITEST"
mkdir DASITEST
fi
return 0
}
uvzneu

Abbildung 12: Das Skript übernimmt Aufgaben, die Sie automatisch schneller und zuverlässiger erledigen.
Zeitstempel und Rechte
Das Werkzeug Find sucht nicht nur nach Namen von Dateien und Verzeichnissen, sondern bezieht bei Bedarf Zeitstempel, Zugriffsrechte und die Dateigröße als Filter mit ein. Um sich mit dem vollen Umfang dieses Befehls vertraut zu machen, werfen Sie am besten einen Blick auf die Manpage. Die Tabelle “Find-Optionen” führt die wichtigsten Möglichkeiten auf.
|
Aktion |
Option |
Hinweis |
|---|---|---|
|
|
nach Typ suchen |
– |
|
|
nach Größe suchen |
– = Höchstgröße, + = Mindestgröße, ohne = gleich |
|
|
nach Zugriffsrechten suchen |
– |
|
|
Dateien neuer als Datei suchen |
– |
|
|
Dateien suchen, die seit N Tagen nicht geändert wurden |
|
|
|
Dateien suchen, auf die seit N Tage nicht zugegriffen wurde |
|
|
|
für gefundene Datei Befehl ausführen |
sicherere Methode |
Die Ausgabe von Find leiten Sie bei Bedarf an eine Pipe weiter oder verarbeiten sie mittels Xargs weiter, das das Ergebnis an weitere Befehle durchreicht, wie etwa Tar. Als Beispiel legt Listing 5 für Dateien je nach deren Änderungsdatum Unterverzeichnisse an und verschiebt sie dorthin. Abbildung 13 zeigt die Ausgangslage, Abbildung 14 den Durchlauf und Abbildung 15 schließlich das Ergebnis.
Listing 5
#!/bin/bash
# $1 = zu bearbeitendes Verzeichnis
if [ -z $1 ]; then
echo "Keine Eingabe"
exit
fi
cd $1
for i in $(stat -c %y:%n * | sort -r | tr \ \:); do
# Variablen uvz (Unterverzeichnis)
# und dn (Dateiname) belegen
uvz=$(echo $i | cut -d \: -f1)
dn=$(echo $i | cut -d \: -f6)
# Falls Verzeichnis, nicht bearbeiten
# und Schleifendurchlauf neu beginnen
if [ -d $dn ]; then
echo "$dn: Verzeichnis, wird ausgelassen"
continue
fi
# uvz gegebenenfalls anlegen und
# Datei nach dort verschieben
if [ -d $uvz ]; then
mv -v $dn $uvz
else
mkdir $uvz
mv -v $dn $uvz
fi
done

Abbildung 14: Ein Skript, das die Metadaten der Dateien auswertet, sortiert diese in eine entsprechende Struktur.

Abbildung 15: In der neuen Verzeichnisstruktur landen die Dateien in entsprechenden Unterverzeichnissen.
Die For-Schleife erhält die Daten mittels Stat. Da Leerzeichen als Trenner dienen, ersetzt es diese durch Doppelpunkte. Die Ausgabe erfolgt nach Datum sortiert, beginnend mit den neuesten Dateien.
In der Schleife enthält die Variable uvz das anzulegende Unterverzeichnis, dn nimmt den Dateinamen auf. Dabei wertet das Skript aus, ob es sich bei dn um ein Verzeichnis handelt, und bricht in diesem Fall die Bearbeitung ab. Die Schleife beginnt dann mit einem neuen Durchlauf. Das verhindert, dass das Skript ein Verzeichnis bearbeitet.
Handelt es sich bei dn dagegen um eine Datei, kontrolliert die Routine anschließend wiederum mittels Test, ob das Unterverzeichnis bereits besteht. Ist das nicht der Fall, legt es den Ordner an und verschiebt anschließend die Datei dorthin. Besteht das Verzeichnis bereits, beschränkt es sich auf Letzteres. Eine optische Kontrolle liefert Tree (Abbildung 15).
Fazit
Mit den geeigneten Shell-Kommandos können Sie verschiedene Eigenschaften von Dateien und Verzeichnissen erkennen, auswerten und ändern. Auf diese Weise lassen sich viele Vorgänge durch Skripte vereinfachen. Das vermeidet gegenüber Klickorgien im Dateimanager Fehler und spart wertvolle Zeit.
Der Autor
Harald Zisler beschäftigt sich seit den frühen 90er-Jahren mit FreeBSD und Linux. Zu Technik- und EDV-Themen verfasst er Bücher und Beiträge für Zeitschriften.









