Mam kilka folderów z \n
charakterem to ich nazwy.
na przykład:
$ ls
''$'\n''Test'
Dotyczy to folderu z nazwą testu i pustą linią przed jego nazwą.
Kiedy więc uruchomię kilka takich skryptów w katalogu nadrzędnym:
while IFS= read -r d; do
rmdir $d
done < <(find * -type d)
To pokazuje:
rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Ponieważ działa dwa razy, raz włączony, \n
a drugi włączony Test
, ponieważ nazwa folderu ma dwie linie.
Jak więc rozwiązać ten problem, aby skrypt wiedział, że \nTest
jest tylko jeden folder?
command-line
bash
scripts
Tara S Volpe
źródło
źródło
-print0
dyrektywy find i-d
opcji read. Zobacz stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done
polecenie ma takie wyjściermdir: failed to remove 'Test': No such file or directory
.rmdir "$file"
Odpowiedzi:
Masz tam tylko jedno polecenie, więc wystarczy zadzwonić
find
z-exec
flagąrmdir
:Lub użyj
-delete
opcji jak wfind -type d -delete
, ale nie będzie działać z niepustymi katalogami. Do tego będziesz potrzebować również-empty
flagi. Uwaga:-delete
sugeruje-depth
, że można to pominąć. Zatem kolejna realna alternatywa, która utrzymuje wszystko jako jeden proces:Jeśli katalog nie jest pusty, użyj
rm -rf {} \;
. Aby wyizolować tylko katalogi z\n
nazwą pliku, możemy połączyć cytowanie ANSI-C basha$'...'
z-name
opozycją:POSIX-ly mogliśmy sobie z tym poradzić w następujący sposób:
Warto wspomnieć, że jeśli twoim celem jest usunięcie katalogów,
-delete
to wystarczy, jednak jeśli chcesz wykonać polecenie w katalogu,-exec
jest to najbardziej odpowiednie.Zobacz też
find
danych wyjściowych?źródło
rm -rf
ostrożnie . ; P Niefind
ma-delete
opcji btw? Usuwa puste katalogi i generuje błędy dla niepustych katalogów typurmdir
- może być tańszy.-delete
nie usuwa niepustych katalogów. Dlatego ostrożne użycierm -rf
find
polecenia bez żadnego niszczącego ładunku (tj. Usuń-delete
lub-exec whatever \;
), aby sprawdzić, czy lista dotkniętych plików jest rzeczywiście poprawna i nie zawiera elementów, które nie powinny zostać usunięte ...find
. Służy-exec rmdir {} +
do grupowania wielu argumentów w jednymrmdir
wierszu poleceń. I BTW „ ale to nie będzie działać z niepustymi katalogami ” . Dotyczy tormdir
również, więc to właściwie nie jest różnica-delete
. To różnica odrm -r
.find -type d -empty -delete
(-delete
implikuje-depth
).Możesz użyć globusów powłoki zamiast
find
:Glob powłoki
*/
dopasowuje wszystkie foldery w bieżącym katalogu. Ta konstrukcja pętli zapewnia automatyczne dzielenie wyrazów automatycznie.Zauważ, że w zależności od opcji powłoki może to zignorować ukryte foldery (nazwa zaczyna się od a.). To zachowanie można zmienić, aby dopasować wszystkie pliki dla bieżącej sesji za pomocą polecenia
shopt -s dotglob
.Nie zapomnij też zawsze podawać swoich zmiennych.
źródło
find
robishopt -s globstar
i używając**/*/
zamiast niej globu.Obie dotychczas napisane odpowiedzi wywołują
rmdir
raz na katalog, ale jakrmdir
można wziąć wiele argumentów, zastanawiam się: czy nie ma bardziej wydajnego sposobu?Można po prostu zrobić
i jest to zdecydowanie najłatwiejszy i najbardziej wydajny sposób, ale może generować błąd w przypadku wielu katalogów (zobacz Jaka jest maksymalna długość argumentów wiersza poleceń w gnome-terminal? ). Jeśli chcesz, aby to podejście działało rekurencyjnie, włącz
globstar
opcję powłoki za pomocąshopt -s globstar
i użyj**/*/
zamiast*/
.Z GNU
find
(i jeśli nie chcemy tylko używać-delete
), możemy to zrobićktóry
xargs
buduje linię poleceń „w taki sam sposób, jak buduje jej linie poleceń” (man find
). Zastępstwo-depth
dla-maxdepth 1
jeśli nie chcesz go do pracy rekurencyjnie.Trzeci i genialny sposób IMO wyjaśnia steeldriver w tej odpowiedzi :
Wykorzystuje to wbudowaną powłokę
printf
do zbudowania listy argumentów rozdzielanej zerami, ta lista jest następnie przesyłana potokowo, doxargs
której wywołańrmdir
dokładnie tak często, jak to konieczne. Można zrobić to praca z rekurencyjnieshopt -s globstar
i**/*/
zamiast*/
jak wyżej.źródło
find
jest rekurencyjny, ale pętla PO nie jest. Aby zreplikować to zachowanie, użyjfind -maxdepth 1 -type d -exec rmdir {} +
. (-depth
w tym przypadku jest zbędny.) Świetna sztuczka zprintf
naśladowaniemfind -print0
, nie widziałem tego wcześniej.ls
iwhile
pętla, brakowało że ich przekierowanie z podstawienia technologicznegofind
zamiast przewodów rurowychls
do pętli i po prostu nie pokazano go z jakiegoś powodu. Tofind *
jest naprawdę pochowane. Tak, jest rekurencyjny i zakończy się niepowodzeniem, jeśli w katalogu jest zbyt wiele pozycji katalogu, w tym katalogów innych niż katalogi, ponieważ nie używa*/
.find .
byłoby znacznie lepiej, ponieważfind
jest szybszestat
niż globalna ekspansja bash.