Zastanawiałem się, czy używanie rm $(ls)
do usuwania plików (lub również rm -r $(ls)
do usuwania katalogów) było bezpieczne? Ponieważ na wszystkich stronach internetowych ludzie dają inne sposoby, aby to zrobić, nawet jeśli to polecenie wydaje się znacznie łatwiejsze niż inne polecenia.
13
touch 'foo -r .. bar'
;rm $(ls)
; gdzie poszedł mój katalog nadrzędny? Jakie alternatywne rozwiązania są jeszcze bardziej skomplikowane?rm *
jest o wiele łatwiejsze do pisania i myślenia oraz bezpieczniejsze (ale nie do końca bezpieczne; patrz odpowiedź Dennisa).ls
mogą się one różnić między implementacjami, a zatem są niestandardowe. W zależności od potrzeb rozważ alternatywne rozwiązania, takie jakfind
istat
. Powinieneś używać gols
wyłącznie do spożycia przez ludzi, nigdy do użycia przez inne polecenia lub skrypty.Odpowiedzi:
Co to ma robić?
ls
wyświetla listę plików w bieżącym katalogu$(ls)
zastępuje dane wyjściowels
miejsc, które jako argumentrm
rm $(ls)
ma na celu usunięcie wszystkich plików w bieżącym kataloguCo jest nie tak z tym obrazem ?
ls
nie może poprawnie obsługiwać znaków specjalnych w nazwie pliku. Użytkownicy systemów uniksowych zazwyczaj zalecają stosowanie różnych podejść . Pokazałem to również w powiązanym pytaniu dotyczącym liczenia nazw plików . Na przykład:Ponadto, jak słusznie wspomniano w odpowiedzi Denisa, nazwę pliku z wiodącymi myślnikami można interpretować jako argument
rm
po zamianie, co nie pozwala na usunięcie nazwy pliku.Co działa
Chcesz usunąć pliki w bieżącym katalogu. Więc użyj glob
rm *
:Możesz użyć
find
polecenia. To narzędzie jest często zalecane w przypadku więcej niż tylko bieżącego katalogu - może rekurencyjnie przechodzić przez całe drzewo katalogów i operować na plikach za pośrednictwem-exec . . .{} \;
Python nie ma problemu ze znakami specjalnymi w nazwach plików, więc możemy to również zastosować (pamiętaj, że ten jest tylko dla plików, będziesz musiał użyć
os.rmdir()
ios.path.isdir()
jeśli chcesz operować na katalogach):W rzeczywistości powyższe polecenie może zostać zmienione w funkcję lub alias
~/.bashrc
dla zwięzłości. Na przykład,Byłaby to wersja Perla
źródło
"$(ls)"
przykład działa tylko wtedy, gdy w katalogu jest tylko jeden plik. Równie dobrze możesz użyć uzupełniania tabulatorami, aby rozwinąć nazwę pliku, ponieważ jest to jedyne uzupełnienie.ls
:) Będę go edytować$(ls)
aby wyłączyć dzielenie słów, albo pozwalasz na dzielenie słów (z katastrofalnymi skutkami). Jedynym czystym sposobem na ominięcie listy wielu ciągów bez traktowania danych jako kodu są zmienne tablicowe lub\0
separator, ale sama powłoka nie może tego zrobić. NadalIFS=$'\n'
jest najmniej niebezpieczny, ale nie może się równaćfind -print0 | xargs -0
. Lubgrep -l --null
. Lub unikniesz całego problemu z takimi rzeczami jakfind -exec rm {} +
. (Zwróć uwagę,+
aby przekazać wiele argumentów do każdego wywołania rm; WAY bardziej wydajny).IFS=$'\n'
w tym przypadku również się nie powiedzie, ponieważ mam nową linię w nazwie pliku, więc dzielenie słów potraktuje to jako dwie nazwy plików zamiast jednej. Dziwnym powodem jest jednak fakt, że przy domyślnejIFS
spacji, tabulacji, nowej linii, oryginalerm "$(ls)"
również powinno się nie powieść, powinno to traktować tak jak powiedziałem nazwę pliku jako dwa osobne, ale tak się nie stało. Zazwyczaj używamfind
z-exec
lubfind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
struktury do czynienia z nazwami plików. Lub można użyćpython
, dodałem przykład tego."$(ls)"
zawsze rozwija się do jednego argumentu, ponieważ cudzysłowy chronią ekspansję$(ls)
przed dzieleniem słów. Tak jak chronią"$foo"
.Nie, to nie jest bezpieczne, a powszechnie stosowana alternatywa
rm *
nie jest dużo bezpieczniejsza.Jest wiele problemów z
rm $(ls)
. Jak już inni ujęli w swoich odpowiedziach, wynikls
zostanie podzielony na znaki obecne w wewnętrznym separatorze pól .Najlepszy scenariusz, po prostu nie działa. W najgorszym przypadku zamierzałeś usunąć tylko pliki (ale nie katalogi) - lub selektywnie usunąć niektóre pliki za pomocą
-i
- alec -rf
w bieżącym katalogu znajduje się plik o nazwie . Zobaczmy co się stanie.Polecenie
rm -i $(ls)
miało usunąć tylko pliki i zapytać przed usunięciem każdego z nich, ale polecenie, które zostało ostatecznie wykonane, przeczytałowięc zrobiło to coś zupełnie innego.
Pamiętaj, że
rm *
jest tylko nieznacznie lepszy. Przy takiej strukturze katalogów jak poprzednio będzie się ona zachowywać zgodnie z przeznaczeniem, ale jeśli masz plik o nazwie-rf
, nadal nie masz szczęścia.Istnieje kilka lepszych alternatyw. Najłatwiejsze są tylko rm i globbing.
Komenda
będzie działać dokładnie zgodnie z przeznaczeniem, gdzie
--
sygnalizuje, że wszystko po nim nie powinno być interpretowane jako opcja.Jest to część wytycznych dotyczących składni narzędzi POSIX od ponad dwóch dekad. Jest szeroko rozpowszechniony, ale nie należy oczekiwać, że będzie obecny wszędzie.
Komenda
powoduje, że glob rozszerza się inaczej, a zatem nie wymaga wsparcia od wywoływanego narzędzia.
W moim przykładzie z góry możesz zobaczyć polecenie, które ostatecznie zostanie wykonane przez wstępne echo .
Czołowe
./
zapobiega rm z przypadkowo leczenia żadnej z nazw takich opcji.źródło
rm
. +1touch 'foo -rf .. bar
. Nie sądzę, aby atakujący mógł uzyskać coś wyższego niż katalog nadrzędny, chyba że możemy wygenerować separator ścieżki wls
danych wyjściowych.rm: refusing to remove '.' or '..' directory: skipping '..'
lub coś podobnego podczas próby usunięcia katalogu nadrzędnego.