Freitag, 2. April 2021

Softlinks in Linux auflösen mit readlink

Ein Softlink in Linux wird mit 

ln -s linkziel linkname

erzeugt.

Dabei darf ein Link auf einen Ordner, eine Datei oder einen anderen Link verweisen.

Durch Letzteres gibt es die Situation, dass man von einem Dateipfad nicht sicher sein kann, dass alle Pfadbestandteile wirklich existieren.

Nehmen wir einen lokalen Pfad a/b/c/datei.txt an.

Dann kann jedes Element darin ein Softlink sein.

Um den echten Pfad aufzulösen gibt es den Linux Befehl readlink.

Ohne Optionen gibt es nur das Endziel des Softlinks nach Auflösung jedes Bestandteils des Pfades aus.

 Mit Option -e müssen alle Bestandteile des Pfades aufgelöst werden können.

Es wird dann der um Softlinks bereinigte vollständige Dateipfad ausgegeben.

Mit Option -f darf der letzte Bestandteil des aufgelösten Dateipfades nicht vorhanden sein; d.h.

Aus a/b/c/datei.txt wird z.B. /d/e/f/g/h/zieldatei.txt.
Dann muss der Pfad /d/e/f/g/h/ existieren und zieldatei.txt darf fehlen im Dateisystem.

 

Mit Option -m werden alle Pfadbestandteile soweit wie möglich aufgelöst und wenn dies nicht möglich so belassen und mit dem Restpfad konkateniert.

 

Fazit:

Nur die Variante mit Option -e macht Sinn.

 

Nachfolgend ein Beispiellauf mit letztem Softlink "mehrpfadig":

 noname@pb:~/todel/linktest$ ls -l
total 4
drwxr-xr-x 3 noname noname 4096 Apr  2 15:44 a
lrwxrwxrwx 1 noname noname    6 Apr  2 15:17 start -> a/lElb
noname@pb:~/todel/linktest$ ls -l a
total 4
drwxr-xr-x 3 noname noname 4096 Apr  2 15:58 b
lrwxrwxrwx 1 noname noname    1 Apr  2 15:44 lEb -> b
lrwxrwxrwx 1 noname noname    3 Apr  2 15:10 lElb -> lEb
lrwxrwxrwx 1 noname noname    2 Apr  2 15:08 lNb2 -> b2
noname@pb:~/todel/linktest$ ls -l a/b
total 4
drwxr-xr-x 3 noname noname 4096 Apr  2 13:05 c
-rw-r--r-- 1 noname noname    0 Apr  2 15:24 fba
lrwxrwxrwx 1 noname noname    3 Apr  2 15:09 lEb -> lEb
lrwxrwxrwx 1 noname noname   18 Apr  2 15:58 lNexisting -> blabla/tests/gsddg
noname@pb:~/todel/linktest$ readlink start/lNexisting
blabla/tests/gsddg
noname@pb:~/todel/linktest$ readlink -e start/lNexisting
noname@pb:~/todel/linktest$ readlink -f start/lNexisting
noname@pb:~/todel/linktest$ readlink -m start/lNexisting
/home/noname/todel/linktest/a/b/blabla/tests/gsddg

   

 Beispiellauf mit letztem Link "einpfadig":

noname@pb:~/todel/linktest$ ln -snf blabla a/b/lNexisting
noname@pb:~/todel/linktest$ ls -l
total 4
drwxr-xr-x 3 noname noname 4096 Apr  2 15:44 a
lrwxrwxrwx 1 noname noname    6 Apr  2 15:17 start -> a/lElb
noname@pb:~/todel/linktest$ ls -l a 
total 4
drwxr-xr-x 3 noname noname 4096 Apr  2 16:17 b
lrwxrwxrwx 1 noname noname    1 Apr  2 15:44 lEb -> b
lrwxrwxrwx 1 noname noname    3 Apr  2 15:10 lElb -> lEb
lrwxrwxrwx 1 noname noname    2 Apr  2 15:08 lNb2 -> b2
noname@pb:~/todel/linktest$ ls -l a/b
total 4
drwxr-xr-x 3 noname noname 4096 Apr  2 13:05 c
-rw-r--r-- 1 noname noname    0 Apr  2 15:24 fba
lrwxrwxrwx 1 noname noname    3 Apr  2 15:09 lEb -> lEb
lrwxrwxrwx 1 noname noname    6 Apr  2 16:17 lNexisting -> blabla
noname@pb:~/todel/linktest$ readlink start/lNexisting
blabla
noname@pb:~/todel/linktest$ readlink -e start/lNexisting
noname@pb:~/todel/linktest$ readlink -f start/lNexisting
/home/noname/todel/linktest/a/b/blabla
noname@pb:~/todel/linktest$ readlink -m start/lNexisting
/home/noname/todel/linktest/a/b/blabla

 

Linux ls Kommando - Was bedeutet total ?

Wenn ein Verzeichnis mit dem Kommando ls -l aufgelistet wird, gibt es ja immer einen Vorspann der Art

noname@pb:~/todel/linktest$ ls -l a/b/c/d/e
total 24
drwxr-xr-x 2 noname noname       4096 Apr  2 13:29 f
drwxr-xr-x 2 noname noname       4096 Apr  2 13:25 f2
drwxr-xr-x 2 noname noname       4096 Apr  2 13:26 f3
drwxr-xr-x 2 noname noname       4096 Apr  2 13:28 f4
drwxr-xr-x 4 noname noname       4096 Apr  2 13:31 f5
-rw-r--r-- 1 noname noname 4194305024 Apr  2 13:52 fa
-rw-r--r-- 1 noname noname          0 Apr  2 13:28 fa2

Was bedeuet die Zahl 24?

Wie man bei GNU coreutils nachlesen kann, ist das die Summe aller direkten Einträge im aktuellen Ordner, dargestellt in der Standard Blockgröße 1024 Bytes ; Standard Blockgröße für die Kommandoausgabe (!=Dateisystemblockgröße).

Es wird hierbei der reale Platzverbrauch der Daten- und Verzeichnisdateien im Ordner berücksichtigt.

Verzeichnisdateien haben unabhängig von ihrem eigenen Inhalt nach ihrer Erzeugung eine konstante und fixe Größe von hier 4096 Bytes.

Die Datendateien können aber sogenannte Sparse Dateien sein, welche nominal größer sein können als ihr realer Plattenverbrauch im Dateisystem.

Man kann eine solche Sparse Datei z.B. mit dd erzeugen, was hier gemacht wurde:

noname@pb:~/todel/linktest$ dd if=/dev/zero of=a/b/c/d/e/fa bs=1k seek=4000k count=1
1+0 Datensätze ein
1+0 Datensätze aus
1024 bytes (1,0 kB, 1,0 KiB) copied, 0,000499488 s, 2,1 MB/s

Die reale Größe läßt sich hiermit anzeigen:

noname@pb:~/todel/linktest$ du -B 1 a/b/c/d/e/fa
4096    a/b/c/d/e/fa

Jetzt schauen wir uns nochmal die Auflistung des Ordners in Bytes an:

noname@pb:~/todel/linktest$ ls -l --block-size="1" a/b/c/d/e
total 24576
drwxr-xr-x 2 noname noname       4096 Apr  2 13:29 f
drwxr-xr-x 2 noname noname       4096 Apr  2 13:25 f2
drwxr-xr-x 2 noname noname       4096 Apr  2 13:26 f3
drwxr-xr-x 2 noname noname       4096 Apr  2 13:28 f4
drwxr-xr-x 4 noname noname       4096 Apr  2 13:31 f5
-rw-r--r-- 1 noname noname 4194305024 Apr  2 13:52 fa
-rw-r--r-- 1 noname noname          0 Apr  2 13:28 fa2

Der Ordner  a/b/c/d/e hat also in Summe seiner direkten Kinder:

realsize(f)+realsize(f2)+realsize(f3)+realsize(f4)+realsize(f5)+realsize(fa)+realsize(fa2)

 folgendes Ergebnis: 4096+4096+4096+4096+4096+4096+0 = 24576

noname@pb:~/todel/linktest$ echo $((4096*6))
24576

Ein nachträgliches befüllen von existierenden Unterordnern ändert nichts an dieser Summe!

Hier am Beispiel des Unterordners f vom betrachteten Ordner e.

Wie man hier sieht, ist der Ordner zu Anfang leer gewesen:

noname@pb:~/todel/linktest$ ls -l --block-size="1" a/b/c/d/e/f
total 0

Jetzt erzeugen wir eine Sparse Datei darin:

noname@pb:~/todel/linktest$ dd if=/dev/zero of=a/b/c/d/e/f/fa3 bs=1k seek=4000k count=1
1+0 Datensätze ein
1+0 Datensätze aus
1024 bytes (1,0 kB, 1,0 KiB) copied, 0,000475806 s, 2,2 MB/s
noname@pb:~/todel/linktest$ du -B 1 --apparent-size a/b/c/d/e/f/fa3
4194305024    a/b/c/d/e/f/fa3
noname@pb:~/todel/linktest$ du -B 1 a/b/c/d/e/f/fa3
4096    a/b/c/d/e/f/fa3
noname@pb:~/todel/linktest$ ls -l --block-size="1" a/b/c/d/e/f
total 4096
-rw-r--r-- 1 noname noname 4194305024 Apr  2 13:57 fa3
 

Die Ursprüngliche Ausgabe von ls für der Ordner e bleibt von dieser Änderung unberührt:

noname@pb:~/todel/linktest$ ls -l --block-size="1" a/b/c/d/e
total 24576
drwxr-xr-x 2 noname noname       4096 Apr  2 13:29 f
drwxr-xr-x 2 noname noname       4096 Apr  2 13:25 f2
drwxr-xr-x 2 noname noname       4096 Apr  2 13:26 f3
drwxr-xr-x 2 noname noname       4096 Apr  2 13:28 f4
drwxr-xr-x 4 noname noname       4096 Apr  2 13:31 f5
-rw-r--r-- 1 noname noname 4194305024 Apr  2 13:52 fa
-rw-r--r-- 1 noname noname          0 Apr  2 13:28 fa2