Aktuellste/älteste Dateien in einem Verzeichniszweig ermitteln

Will man in einem einzelnen Verzeichnis die aktuellsten (oder ältesten) Dateien finden, geht das mit den Sortierungs-Optionen von ls:

ls -tr | tail

zeigt die neusten Dateien an (aktuellste am Ende). Umgekehrt für die ältesten:

ls -t | tail

Will (oder muss 😉 ) man aber eine ganze Verzeichnisstruktur durchsuchen, geht das mit ls nicht. Hier muss man find und stat zu Hilfe nehmen:

find . -exec stat --format '%y %n' {} ; | sort | tail

So erhält man die neusten Dateien, z.B.:

2010-11-08 10:55:49.000000000 +0100 ./javascript/selectm.js
2010-11-08 10:55:59.000000000 +0100 ./Formulareinm.php
2010-11-08 10:57:16.000000000 +0100 ./Eintragenm.php
2012-04-02 10:52:40.000000000 +0200 ./nop.html
2012-04-02 11:02:00.000000000 +0200 ./.htaccess
2012-07-10 17:06:16.000000000 +0200 ./phpinclude/autoabfrage.inc
2012-07-10 17:13:34.000000000 +0200 ./phpinclude/ergebnis.inc
2014-03-04 16:17:58.000000000 +0100 ./phpinclude
2018-10-23 10:22:02.000000000 +0200 ./phpinclude/send_infoMail.inc
2019-04-26 11:51:36.000000000 +0200 .

Will man die ältesten, so muss man die Reihenfolge mit den Sort-Parameter -r umkehren:

find . -exec stat --format '%y %n' {} ; | sort -r | tail

Zwei Output-Streams zusammenfassen

In einem Tweet von climagic gab es einen Tipp, wie man die Ausgabe von zwei (oder mehreren) Programmen in der Shell zusammenfassen und als Eingabe für ein anderes Kommando nutzen kann:

{ find /one; find /two; } | tar zcvf one-and-two.tar.gz -T -

Das kann nicht nur dazu dienen, um mehrere verschiedene Verzeichnisse zu taren (mit -T - werden die zu archivierenden Dateinamen über die Std-Eingabe übermittelt), man kann beispielsweise auch mehrere greps zusammenfassen.

Shell: Zeitstempel in die Ausgabe einfügen

Loggt man innerhalb eines Shellskripts in eine Logdatei, so ist es häufig sinnvoll, den Einträgen einen Zeitstempel voran zu stellen. Das macht das kleine Tool ts (von Timestamp) ganz einfach:

echo "Eine ganz wichtige Meldung" | ts '[%Y-%m-%d %H:%M:%S]' >> meine-Logdatei

Das Tool ts ist Bestandteil von moreutils, das Paket muss also ggf. erst installiert werden. Will/kann man das nicht, kann man sich auch mit awk, perl und anderen Tools helfen. Wie das geht, ist in einem Post auf StackExchange erklärt (wo ich auch den Tipp mit ts her habe).

Dateien mit find suchen und verschieben

Will man Dateien, die sich per find finden lassen, in ein anderes Verzeichnis verschieben, gelingt das nur mit ein paar kleinen Tricks.

Beispielsweise sollen in einem Doku-Wiki-Verzeichnis alle zu foo.txt gehörenden Dateien in das Unterverzeichnis bar verschoben werden (wobei die entspr. bar-Verzeichnisse bereits existieren). Man denk natürlich zunächst an so was:

find . -name "foo*" -exec mv "{} `dirname {}`/bar/`basename {}`" ;

Leider funktioniert das so nicht, weil dirname {} nur . (einen Punkt) zurück liefert.

Nun kann man dirname ja durch ${VAR%/*} ersetzen, aber das funktioniert mit find nur in einer Sub-Shell:

find . -name "foo*" -ok sh -c 'mv -v $0 ${0%/*}/bar/${0##*/}' {} ;

Das funktioniert und dank -ok statt -exec fragt find vor jeder Befehlsausführung, ob das tatsächlich gemacht werden soll. Dabei fällt dann auf, dass find auch gerne die gerade eben verschobene Datei nochmal verschieben möchte. Um das zu verhindern, muss der Zielpfad ausgeklammert werden. Das gelingt so:

find . -name "foo*" -not -path '*/bar/*' -ok sh -c 'mv -v $0 ${0%/*}/bar/${0##*/}' {} ;

In einem Tar-Archiv die größten Dateien ermitteln

Wie in „Tar-Archive vergleichen“ beschrieben, werden Backups manchmal plötzlich größer. Wenn man nun einfach wissen möchte, welches denn die größten Dateien in dem Archiv sind, geht das ohne viel Aufwand mit

tar tvf 20141117.tgz | sed 's/ \{1,\}/\t/g' | cut -f 3,6 | sort -n | tail

Hierbei werden durch sed alle aufeinanderfolgende Leerzeichen durch ein Tab-Zeichen ersetzt, so dass dann die relevanten Spalten per cut ausgeschnitten werden können. Anschließend wird nummerisch sortiert und mit tail die Ausgabe begrenzt.

Tar gibt die Größe in Bytes aus. Leider kenne ich keine Option, mit welcher sich bei tar die Anzeige der Größe beeinflussen lässt.

Prüfen, ob es im Verzeichnis neue Dateien gibt

Neulich hatte ich die Aufgabe zu prüfen, ob es in einer Reihe von Unterverzeichnissen aktuelle Dateien gibt (d.h.: ob die Backups tatsächlich was übertragen hatten und wo es nicht funktioniert hatte). Die zu prüfenden Verzeichnisse waren allesamt Unterverzeichnisse von netdir, so dass man gut mit einer For-Schleife arbeiten kann:

cd netdir
for dir in `ls -1`
do
   echo $dir
   cd $dir > /dev/null || exit 99
   res=`find . -mtime -2 -type f`
   if [ -z "$res" ]
   then
      echo "$dir - nichts aktuelles gefunden!"
   fi
   cd ..
done

Wenn es also in dem zu prüfenden Verzeichnis keine Datei gibt, die jünger als zwei Tage ist, wird „nichts aktuelles gefunden!“ gemeldet.

Tar-Archive vergleichen

Ich sichere bestimmte Verzeichnisse von Rechnern täglich in Tar-Archiven (siehe auch „Verzeichnisse auf einen anderen Rechner übertragen“). Nun kommt es vor, dass diese Archive plötzlich oder auch mit der Zeit größer werden. Dann will man natürlich wissen, wieso. Um im ersten Schritt zu vermeiden, dass ich die Archive auspacken und dann vergleichen muss, lese ich den Inhalt zwei Tar-Dateien aus, bereite sie mittels sed auf und vergleiche sie mit diff:

tar tvf 20140822.tgz | sed 's/^([a-zA-Z-]{1,}) ([^[:blank:]]{1,}) {1,}([0-9]{1,}) .* (.*)$/4 3/' > 20140822.content 
tar tvf 20140901.tgz | sed 's/^([a-zA-Z-]{1,}) ([^[:blank:]]{1,}) {1,}([0-9]{1,}) .* (.*)$/4 3/' > 20140901.content
diff -y -W 200 --suppress-common-lines 20140822.content 20140901.content > 20140822vs20140901

Sofern sich nicht all zu viele Dateien geändert haben oder dazu gekommen sind, kann das Ergebnis schon erste Hinweise geben. Ansonsten muss man mit den üblichen Werkzeugen (z.B. grep) weiter filtern und analysieren.

Empfehlungsoption nicht empfehlenswert

Der BGH hat in einem Urteil die vielfach auf Webseiten eingesetzte Empfehlungsfunktion weitgehend verboten.

Dem Bericht im Absolit-Blog nach sieht das Gericht die via Tell-a-Friend versandte E-Mail als Spam an – insbesondere, wenn als Absender-Adresse die des beworbenen Unternehmens verwendet wird.

Man sollte also, wenn auf die Funktion nicht verzichtet werden soll, Namen und E-Mai-Adresse des empfehlenden Benutzer verwenden und ihm zu ermöglichen Betreff und Text der Mail selbst zu editieren. Rechtssicherheit besteht dann aber nach wie vor nicht.

Mehr zum Urteil im Artikel „BGH untersagt Tell-a-friend weitgehend“ auf absolit.de

Unix-Kommandozeile

Alle Scripte im aktuellen Verzeichnis greppen

Heute hatte ich den Fall, dass ich in einem Verzeichnis alle Perl- und Shell-Scripte nach dem Wort „gtar“ durchsuchen musste. Leider befanden sich in dem Verzeichnis nicht nur Scripte, sondern auch, zum Teil recht große, Binär-Dateien, die ich ausklammern wollte. Entstanden ist der folgende Einzeiler:

for FILE in `ls -1`; do if `file $FILE | grep -q Befehlstext >/dev/null`; then grep -l gtar $FILE; fi; done

Das funktioniert unter HP-UX, bei Linux ist file gesprächiger und muss daher auf den MIME-Type begrenzt werden:

for FILE in `ls -1`; do if `file --mime-type $FILE | egrep -e '(x-perl|x-shellscript)' >/dev/null`; then grep -l gtar $FILE; fi; done