Datei entfernen, aber nur, wenn es sich um einen Symlink handelt

11

Idealerweise hätte ich gerne einen solchen Befehl

rm --only-if-symlink link-to-file

weil ich mich zu oft verbrannt habe, um versehentlich die Datei zu löschen, anstatt den Symlink, der auf die Datei verweist. Dies kann besonders schlimm sein, wenn sudo beteiligt ist. Jetzt mache ich natürlich eine ls -al, um sicherzustellen, dass es sich wirklich um einen Symlink und dergleichen handelt, aber das ist anfällig für Bedienerfehler (ähnlich benannte Datei, Tippfehler usw.) und Rennbedingungen (wenn jemand wollte, dass ich aus irgendeinem Grund eine Datei lösche). Gibt es eine Möglichkeit zu überprüfen, ob eine Datei ein Symlink ist, und sie nur zu löschen, wenn sie sich in einem Befehl befindet?

Shelvacu
quelle
1
Ich denke nicht, dass die Rennbedingungen ein Problem sein sollten. Jeder, der den Symlink entfernen und durch eine Datei ersetzen kann, benötigt eine Schreibberechtigung für das Verzeichnis, dh er kann die Datei auch selbst löschen.
Nate Eldredge

Antworten:

19
 $ rm_if_link(){ [ ! -L "$1" ] || rm -v "$1"; }

 #test
 $ touch nonlink; ln -s link
 $ rm_if_link nonlink
 $ rm_if_link link
   removed 'link'     
PSkocik
quelle
4
Sicherlich wäre es klar sein , zu entfernen !und ändern ||zu&&
glenn jackman
5
@glennjackman Ich habe es mir zur Gewohnheit gemacht, die ||Form zu bevorzugen . &&bringt Dinge runter, wenn Sie im set -eModus sind.
PSkocik
@PSkocik Das ist im Allgemeinen riskant, da es nicht zwischen dem interessanten Fall (die Datei existiert und ist ein Symlink) und anderen Gründen für einen Exit-Code ungleich Null, wie z. B. einem leeren Wert ohne Anführungszeichen ( [ ! -L $1 ]), unter Verwendung eines ungültigen Operators ( [ ! -l foo ]) oder sogar Syntaxfehler ( [ ! -q foo || echo foo)
l0b0
2
@XiongChiamiov Das Problem dabei rm_if_link(){ [ -L "$1" ] && rm -v "$1"; }ist, dass das Ausführen auf einem Nicht-Link- set -e Modus Ihren Shell-Prozess beendet. Sie könnten anhängen, || :aber dann wird es meiner Meinung nach noch weniger klar als die ! ||Version, und es wird verhindert, dass ein rmFehler Sie umbringt set -e, was wahrscheinlich unerwünscht ist. ! ||ist ziemlich prägnant und klar und leidet unter keinem dieser Probleme.
PSkocik
1
Nein . Andere Optionen: a) Setzen Sie das rmInnere in Ihren Test ein, b) Verwenden Sie eine tatsächliche if-Anweisung, c) Verwenden Sie keine -einteraktiven Shells (und testen Sie Ihre Skripte!). Wenn Sie über die Lesbarkeit streiten möchten, ifist es ziemlich eindeutig der Gewinner , zu testen, ob etwas ein Link ist.
Boykott SE für Monica Cellio
5

Sie können mit findihrer und -type lTestbedingung (siehe dort Tests , wenn das Objekt gefunden ist eine l Tinte oder nicht)

Wenn Sie beispielsweise eine Datei fooim aktuellen Verzeichnis haben, können Sie dies tun:

$ find . -type l -iname "foo" -delete

Möglicherweise können Sie dies mit nur folgenden Funktionen vereinfachen:

$ find . -maxdepth 1 -type l -delete

Womit alle Symlinks im aktuellen Verzeichnis gelöscht würden.

Warnung:

Die -deleteOption in findist wirklich sehr, sehr gefährlich. Stellen Sie sicher, dass Sie es am Ende des Suchbefehls platzieren. Wenn Sie es falsch platzieren, wird alles gelöscht, was es findet, unabhängig davon, ob die Ergebnisse Ihrer Bedingung entsprechen.

Wie in den Kommentaren vorgeschlagen, besteht eine sicherere Option darin, findund rm -i(was Sie zwingt, das Entfernen von Dateien zu bestätigen) in Verbindung zu verwenden:

$ $ find . -type l -iname "foo" | xargs rm -i

Persönlich -exec trash {} \;lösche ich Dateien vorübergehend, weil ich wie Sie rmin der Vergangenheit von gebrannt wurde . Double geht für eine falsch platzierte -deleteFlagge.

http://slackermedia.ml/trashy

Klaatu von Schlacker
quelle
1
Anstelle von -delete können Sie es einfach ausdrucken und an xargs übergeben: find . -type l -iname "foo" | xargs rm -i Es ist sicherer.
Boban P.
1
Ich mag die Verwendung von @BobanP. aus rm -iSicherheitsgründen.
Klaatu von Schlacker
3
"Dies würde alle Symlinks im aktuellen Verzeichnis löschen" ... und jeden Punkt darunter.
Joseph R.
1
Als @JosephR. sagte, es wird den ganzen Weg die Straße hinunter gehen. Fügen Sie -maxdepth 1 in find hinzu.
Boban P.
1
Bricht immer noch bei Dateinamen mit Leerzeichen ab. Schlagen Sie vor, -print0für findund -0für zu verwenden xargs.
Wildcard
4
zsh -c 'rm foo(@)'

@ist ein Glob-Qualifier ; Das Muster foo(@)stimmt mit dem fooüberein, was übereinstimmt, aber nur mit den symbolischen Links.

foo(-@)würde nur mit defekten symbolischen Links übereinstimmen. foo(@,L0)würde nur symbolischen Links und leeren Dateien entsprechen.

Wenn Sie zsh ausführen, müssen Sie natürlich nur tippen rm foo(@). Sie müssen darauf achten, Entervor dem Tippen nicht zu drücken (@).

Gilles 'SO - hör auf böse zu sein'
quelle
1
Zsh klingt immer mächtiger, wenn ich solche Antworten sehe.
Jeff Schaller