Layer 8Ehrlicher Tech-Support

Linux: ctime ist nicht das Erstellungsdatum einer Datei

ls -lc und die Change-Zeile von stat zeigen nicht, wann eine Datei angelegt wurde, sondern die letzte Statusänderung. Ein chmod genügt schon.

Aufwand:
ca. 15 Min.
Voraussetzung:
Ein Terminal, stat und ls aus GNU coreutils, find aus GNU findutils
Gilt für:
Linux (inode(7) aus Linux man-pages 6.19; stat(1) und ls(1) aus GNU coreutils 9.11; find(1) aus GNU findutils, Stand 12.10.2025)

Das Symptom

Gesucht ist das Erstellungsdatum einer Datei, etwa um zu klären, seit wann ein Bericht auf dem Server liegt. ls -lc liefert eine Zeit, stat hat eine Zeile namens Change, und das c klingt so verlässlich nach created, dass niemand weiter nachdenkt. Ergebnis: Die Datei wurde angeblich gestern angelegt. Tatsächlich liegt sie seit Monaten dort, und gestern hat nur ein Backup- oder Verteilungsprogramm ihre Rechte oder ihren Eigentümer neu gesetzt.

Auf einem deutsch eingestellten System wird es nicht besser. GNU stat übersetzt seine Zeilen; in der hier geprüften Fassung 9.7 heißt die Zeile für ctime Geändert und die für mtime Modifiziert, was zusammen eher nach Synonymen klingt als nach zwei verschiedenen Dingen. Am teuersten wird die Verwechslung in Skripten: Ein Aufräumjob, der alte Dateien mit find -ctime aussortiert, verschont alles, dessen Rechte kürzlich jemand angefasst hat.

Die „Layer 8“-Wahrheit

Linux führt für jede Datei mehrere Zeitstempel, und keiner von ihnen heißt creation, nur weil er mit c anfängt. inode(7) definiert ctime so: „This is the file’s last status change timestamp. It is changed by writing or by setting inode information (i.e., owner, group, link count, mode, etc.).“ Ein chmod, ein chown, ein neuer harter Link: Jede dieser Kleinigkeiten setzt ctime auf jetzt, ohne dass sich am Inhalt ein Byte geändert hat. Die mtime bleibt in diesen Fällen stehen, und auch das steht ausdrücklich dort: „The mtime timestamp is not changed for changes in owner, group, hard link count, or mode.“

Das echte Anlegedatum ist ein eigenes Feld, btime. inode(7) beschreibt es knapp: „The file’s creation timestamp. This is set on file creation and not changed subsequently.“ Es steckt nicht in der klassischen stat-Struktur, sondern nur in statx, und die Handbuchseite hängt eine Warnung an: „The btime timestamp was not historically present on UNIX systems and is not currently supported by most Linux filesystems.“ Ob das eigene Dateisystem dazugehört, zeigt stat selbst: %w gibt laut stat(1) einen Strich aus, wenn die Zeit unbekannt ist.

Der Layer-8-Fehler ist also ein Lesefehler mit Folgen. ls(1) sagt bei der Option -c klar, was angezeigt wird, nämlich die ctime als „time of last change of file status information“. stat beschriftet die Zeile mit Change, nicht mit Created. Und find unterscheidet zwischen geänderten Daten und geändertem Status. Wer das Alter des Inhalts meint, nimmt mtime. Wer das Anlegen meint, nimmt btime, falls es sie gibt. ctime ist für keine dieser Fragen die richtige Antwort, sondern beantwortet eine dritte: Wann hat zuletzt jemand an den Verwaltungsdaten dieser Datei gedreht?

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    stat lesen, und zwar alle vier Zeilen

    stat zeigt für eine Datei vier Zeiten: Access, Modify, Change und Birth. Auf einem deutsch eingestellten System übersetzt GNU stat die Bezeichnungen; Change erscheint dort in der hier geprüften Fassung 9.7 als Geändert, was nach Inhaltsänderung klingt. Mit LC_ALL=C vor dem Befehl erscheinen die englischen Namen, die zu den Handbuchseiten passen. Change ist die Statusänderung, Modify der Inhalt, Birth das Anlegen.

    LC_ALL=C stat bericht.txt
    
  2. 2.

    Die Gegenprobe selbst machen

    Wer es sehen will, legt eine Testdatei an, liest die drei interessanten Zeiten, ändert nur die Rechte und liest erneut. Nach dem chmod ist Change auf die aktuelle Zeit gesprungen, Modify und Birth sind unverändert. Das ist genau die Definition aus inode(7): ctime ändert sich beim Setzen von Inode-Informationen wie dem Modus, mtime nicht. Ein Beleg in zehn Sekunden.

    echo test > probe.txt
    stat -c 'Birth: %w | Modify: %y | Change: %z' probe.txt
    chmod 600 probe.txt
    stat -c 'Birth: %w | Modify: %y | Change: %z' probe.txt
    
  3. 3.

    Das Anlegedatum über birth abfragen

    Wer wissen will, wann eine Datei angelegt wurde, fragt die Geburtszeit ab: in stat über %w, in ls über --time=birth zusammen mit -l. Steht bei %w ein Strich, kennt das System diese Zeit für die Datei nicht. Dann ist das Anlegedatum schlicht nicht ermittelbar, und ctime ist kein Ersatz dafür, sondern nur eine andere, falsche Antwort auf dieselbe Frage.

    ls -l --time=birth bericht.txt
    
  4. 4.

    Aufräumskripte auf die richtige Zeit umstellen

    find unterscheidet sauber: -mtime prüft laut find(1), wann die Daten zuletzt geändert wurden, -ctime, wann der Status zuletzt geändert wurde. Ein Skript, das alte Dateien mit -ctime sucht, hält jede Datei für frisch, deren Rechte gestern ein Backup- oder Verteilungsprogramm angefasst hat. Bruchteile von Tagen ignoriert find dabei; +30 trifft also Dateien, deren Änderung mindestens 31 volle Tage zurückliegt. Erst auflisten, dann über Löschen nachdenken.

    find /srv/ablage -type f -mtime +30
    
  5. 5.

    Mit fehlender Geburtszeit ehrlich umgehen

    Liefert das Dateisystem keine Geburtszeit, schlagen in find alle Tests fehl, die sich auf sie beziehen; find(1) beschreibt das ausdrücklich. Das ist kein Fehler des Werkzeugs, sondern die korrekte Auskunft, dass die Information fehlt. Wer das Anlegedatum von Dateien wirklich braucht, muss es dann selbst festhalten, etwa im Dateinamen oder in einer Datenbank, statt es nachträglich aus ctime zu erraten.

Häufige Fragen (FAQ)

?Wofür steht das c in ctime, wenn nicht für creation?

Für change, genauer für die Änderung der Statusinformationen. ls(1) beschreibt die Option -c als Anzeige der ctime, der „time of last change of file status information“. inode(7) nennt das Feld „last status change timestamp“. Gemeint sind die Verwaltungsdaten im Inode, nicht der Inhalt und schon gar nicht der Zeitpunkt des Anlegens. Das c ist also ein Kürzel, das in die Irre führt, und die deutsche Übersetzung der stat-Ausgabe macht es eher schlimmer als besser.

?Warum hat sich ctime geändert, obwohl niemand den Inhalt angefasst hat?

Weil ctime laut inode(7) nicht nur beim Schreiben neu gesetzt wird, sondern auch, wenn Inode-Informationen geändert werden, nämlich Eigentümer, Gruppe, Linkzahl oder Modus. Ein chmod, ein chown oder ein zusätzlicher harter Link genügen also. Die mtime bleibt dabei stehen; inode(7) schreibt ausdrücklich, dass sie bei Änderungen an Eigentümer, Gruppe, Linkzahl oder Modus nicht verändert wird. Genau daran erkennt man den Fall: Change ist neu, Modify ist alt.

?Wo steht dann das echte Erstellungsdatum?

Im Feld btime, das inode(7) als „File creation (birth) timestamp“ beschreibt: beim Anlegen gesetzt und danach nicht mehr verändert. Es steckt nicht in der klassischen stat-Struktur, sondern ist nur über statx erreichbar. stat zeigt es mit dem Formatzeichen %w, ls mit --time=birth. Ist die Zeit unbekannt, gibt %w laut stat(1) einen Strich aus. inode(7) warnt außerdem, dass btime auf UNIX historisch nicht existierte und von den meisten Linux-Dateisystemen derzeit nicht unterstützt wird.

?Was zeigt ls -l eigentlich für eine Zeit an?

Standardmäßig die mtime, also den Zeitpunkt der letzten Änderung des Inhalts. ls(1) führt bei der Option --time die Änderungszeit ausdrücklich als Voreinstellung und listet daneben die Zugriffszeit (-u), die Statusänderung (-c) und die Geburtszeit (birth oder creation). Mit -l bestimmt dieses Wort, welche Zeit angezeigt wird. Wer also ls -lc tippt, sieht nicht das Anlegedatum, sondern die letzte Statusänderung, und sortiert wird dabei nach Namen, nicht nach Zeit.

?Und die Zugriffszeit atime, taugt die wenigstens als Hinweis auf die Nutzung?

Nur eingeschränkt. inode(7) beschreibt atime als Zeit des letzten Zugriffs, die etwa durch read(2) mit mehr als null Bytes gesetzt wird; ob mmap(2) sie aktualisiert, ist dort ausdrücklich offen. Außerdem erlauben manche Dateisysteme, so eingehängt zu werden, dass Zugriffe die atime nicht aktualisieren; inode(7) verweist dazu auf noatime, nodiratime und relatime. Eine alte atime beweist deshalb nicht, dass niemand die Datei gelesen hat.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

OSLästigArgument list too long

bash: Argument list too long

Der Befehl bricht mit 'Argument list too long' ab, weil ein * zu viele Dateien liefert. So löst du es mit find und xargs statt Globbing.

OSLästigPermission denied

Permission denied, obwohl man root ist

Selbst als root verweigert das System den Zugriff. Meist ist das Dateisystem schreibgeschützt eingehängt oder die Datei ist unveränderlich.