Usuń plik, ale tylko jeśli jest to dowiązanie symboliczne

11

Idealnie chciałbym takie polecenie

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

ponieważ spaliłem się zbyt wiele razy przypadkowo usuwając plik zamiast dowiązania symbolicznego wskazującego na plik. Może to być szczególnie złe, gdy zaangażowane jest sudo. Teraz oczywiście robię to, ls -alaby upewnić się, że naprawdę jest to dowiązanie symboliczne i takie, ale jest podatne na błąd operatora (podobnie nazwany plik, literówka itp.) I warunki wyścigu (jeśli ktoś z jakiegoś powodu chciał mnie usunąć). Czy jest jakiś sposób, aby sprawdzić, czy plik jest dowiązaniem symbolicznym i usunąć go tylko, jeśli jest w jednym poleceniu?

Shelvacu
źródło
1
Nie sądzę, że wyścig powinien być problemem. Każdy, kto byłby w stanie usunąć dowiązanie symboliczne i zastąpić go plikiem, musiałby mieć uprawnienia do zapisu w katalogu, co oznacza, że ​​mógłby również sam usunąć plik.
Nate Eldredge

Odpowiedzi:

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
źródło
4
Z pewnością łatwiej byłoby usunąć !i zmienić ||na&&
glenn jackman
5
@glennjackman Przyzwyczaiłem się preferować ||formę. &&obniża poziom, jeśli jesteś w set -etrybie.
PSkocik
@PSkocik Zasadniczo jest to ryzykowne, ponieważ nie rozróżnia interesującego przypadku (plik istnieje i jest dowiązaniem symbolicznym) oraz innych przyczyn niezerowego kodu wyjścia, takich jak pusta niecytowana wartość ( [ ! -L $1 ]), przy użyciu niepoprawnego operatora ( [ ! -l foo ]), a nawet błąd składniowy ( [ ! -q foo || echo foo)
l0b0
2
@XiongChiamiov Problem rm_if_link(){ [ -L "$1" ] && rm -v "$1"; }polega na tym, że uruchomienie go w set -e trybie bez dowiązania zabije proces powłoki. Możesz dołączyć, || :ale wtedy staje się, IMHO, jeszcze mniej wyraźne niż ! ||wersja, i zapobiegnie to rmzabiciu cię przez niepowodzenie set -e, co jest prawdopodobnie niepożądane. ! ||jest dość zwięzły i jasny i nie cierpi na żaden z tych problemów.
PSkocik
1
Nope . Inne opcje: a) umieść rmtest w swoim wnętrzu, b) użyj rzeczywistej instrukcji if, c) nie chodź za pomocą -ewewnętrznych interaktywnych powłok (i przetestuj swoje skrypty!). Jeśli chcesz spierać się o czytelność, skorzystanie ifz testu, czy coś jest linkiem, jest wyraźnie zwycięzcą.
Bojkot SE dla Moniki Cellio
5

Można użyć find, a jego -type lstan testu (który sprawdza, jeśli okazało się, że obiekt jest l atrament lub nie)

Na przykład, jeśli masz plik o nazwie foow bieżącym katalogu, możesz to zrobić:

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

Możesz to uprościć za pomocą:

$ find . -maxdepth 1 -type l -delete

Co spowoduje usunięcie wszystkich dowiązań symbolicznych w bieżącym katalogu.

Ostrzeżenie:

-deleteOpcja w findto naprawdę bardzo niebezpieczne. UPEWNIJ SIĘ, ŻE UMIESZCZASZ NA KOŃCU ZNAJDUJĄCEGO POLECENIA Jeśli go zgubisz, usunie wszystko, co znajdzie, niezależnie od tego, czy wyniki są zgodne z twoim warunkiem.

Jak sugerowano w komentarzach, bezpieczniejszą opcją może być użycie findi rm -i(co zmusza do potwierdzenia usunięcia pliku) w połączeniu:

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

Osobiście używam -exec trash {} \;do tymczasowego usuwania plików, ponieważ ja, podobnie jak ty, zostałem spalony rmw przeszłości. Podwójnie oznacza źle umieszczoną -deleteflagę.

http://slackermedia.ml/trashy

Klaatu von Schlacker
źródło
1
Zamiast -delete możesz po prostu wydrukować go i przekazać do xargs: find . -type l -iname "foo" | xargs rm -i jest bezpieczniej.
Boban P.
1
Na pewno podoba mi się użycie @ BobanP rm -idla bezpieczeństwa.
Klaatu von Schlacker,
3
„Spowoduje to usunięcie wszystkich dowiązań symbolicznych w bieżącym katalogu” ... i dowolnego punktu poniżej.
Joseph R.
1
Jako @JosephR. powiedział, że pójdzie całą drogę. Dodaj -maxdepth 1 w find.
Boban P.
1
Nadal łamie nazwy plików spacjami. Zaproponuj użycie -print0for findi -0for xargs.
Wildcard
4
zsh -c 'rm foo(@)'

@jest kwalifikatorem globalnym ; wzór foo(@)pasuje do tego foo, co pasuje, ale tylko do dowiązań symbolicznych.

foo(-@)pasowałyby tylko zepsute dowiązania symboliczne foo(@,L0)pasowałyby tylko dowiązania symboliczne i puste pliki.

Oczywiście, jeśli korzystasz z ZHS, po prostu musisz wpisać rm foo(@). Trzeba uważać, aby nie naciskać Enterprzed pisaniem (@).

Gilles „SO- przestań być zły”
źródło
1
Zsh brzmi coraz mocniej, gdy widzę takie odpowiedzi.
Jeff Schaller