per loop in cartelle con \ n carattere nei loro nomi


9

Ho alcune cartelle con \ncarattere i loro nomi.

per esempio:

$ ls
''$'\n''Test'

Questo si riferisce a una cartella con il nome del test e una riga vuota prima del suo nome.

Quindi, quando eseguo alcuni script come questo, nella sua directory principale:

while IFS= read -r d; do 
    rmdir $d
done < <(find * -type d)

Mostra:

rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory

Perché viene eseguito due volte, una volta acceso \ne l'altro acceso Test, perché il nome della cartella ha due righe.

Quindi, come posso risolvere questo problema in modo tale che lo script sappia che \nTestè solo una cartella?


3
Devi usare la -print0direttiva find e l' -dopzione read. Vedere stackoverflow.com/a/40189667/7552
Glenn Jackman

1
@glennjackman Per favore, rispondi!
dessert

@glennjackman Grazie per la risposta ma il find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; donecomando ha questo output rmdir: failed to remove 'Test': No such file or directory.
Tara S Volpe,

5
È necessario citare la variabile:rmdir "$file"
Glenn Jackman

1
@glennjackman Invia questo come risposta. È una soluzione adeguata e inoltre i commenti non sono il posto migliore per quello. Il voto già implicito :)
Sergiy Kolodyazhnyy il

Risposte:


12

Hai solo un comando lì, quindi è sufficiente chiamare findcon -execflag di chiamata rmdir:

find -depth -type d -exec rmdir {} \;

Oppure usa l' -deleteopzione come in find -type d -delete, ma non funzionerà con le directory non vuote. Per questo avrai anche bisogno di -emptybandiera. Nota anche, -deleteimplica -depthche potrebbe essere saltato. Quindi un'altra alternativa praticabile che mantiene tutto come un processo:

find -type d -empty -delete

Se la directory non è vuota, utilizzare rm -rf {} \;. Per isolare solo le directory con \nnel nome file possiamo combinare la quotazione ANSI-C di bash $'...'con l' -nameopposizione:

find  -type d -name $'*\n*' -empty -delete

POSIX, potremmo gestirlo in questo modo:

find -depth  -type d -name "$(printf '*\n*' )" -exec rmdir {} \;

Vale la pena ricordare che se il tuo obiettivo è la rimozione di directory, allora -deleteè sufficiente, tuttavia se si desidera eseguire un comando sulla directory, -execè più appropriato.

Guarda anche


2
... usare rm -rf con cura . ; P Non findha -deleteun'opzione tra l'altro? Elimina le directory vuote e genera errori per quelli non vuoti come rmdir- potrebbe essere meno costoso.
dessert

3
@dessert Lo fa e l'ho aggiunto, ma -deletenon rimuoverò le directory non vuote. Quindi, l' uso attento dirm -rf
Sergiy Kolodyazhnyy il

6
Esegui sempre a secco tali findcomandi senza alcun payload distruttivo (ovvero rimuovi il -deleteo -exec whatever \;) per verificare se l'elenco dei file interessati è effettivamente corretto e non contiene elementi che non devono essere eliminati ...
Byte Commander

2
Questo è askubuntu.com in modo da poter assumere GNU find. Utilizzare -exec rmdir {} +per raggruppare più arg su una rmdirriga di comando. E BTW " ma non funzionerà con directory non vuote " si applica rmdiranche a, quindi non è in realtà una differenza da -delete. È una differenza da rm -r.
Peter Cordes,

2
find -type d -empty -delete( -deleteimplica -depth).
Kevin,

10

È possibile utilizzare globs shell invece di find:

for d in */ ; do 
    rmdir "$d"
done

Il shell glob */corrisponde a tutte le cartelle nella directory corrente. Questa costruzione for-loop si occupa automaticamente della corretta suddivisione delle parole.

Si noti che a seconda delle opzioni della shell, questo potrebbe ignorare le cartelle nascoste (nome che inizia con a.). Questo comportamento può essere modificata in base tutti i file per la sessione corrente utilizzando il comando shopt -s dotglob.

Inoltre, non dimenticare di citare sempre le tue variabili.


il glob troverà solo file / directory nella directory corrente, non ricorsivamente come findfa
ilkkachu,

1
Hai ragione @ilkkachu. Ciò potrebbe essere modificato abilitando l'opzione della shell globstar shopt -s globstare usando **/*/invece un glob.
Byte Commander

6

Entrambe le risposte scritte finora chiamano rmdiruna volta per directory, ma come rmdirposso prendere più argomenti mi chiedo: non c'è un modo più efficiente?

Si potrebbe semplicemente fare

rmdir */

e questo è sicuramente il modo più semplice ed efficiente, ma potrebbe generare un errore nel caso di molte directory (vedi Qual è la lunghezza massima degli argomenti della riga di comando in gnome-terminal? ). Se si desidera che questo approccio funzioni in modo ricorsivo, abilitare l' globstaropzione shell con shopt -s globstare utilizzare **/*/invece di */.

Con GNU find(e se non vogliamo solo usarlo -delete), potremmo farlo

find -depth -type d -exec rmdir {} +

che crea la riga di comando "più o meno allo stesso modo in cui xargscrea le sue righe di comando" ( man find). Sostituto -depthper -maxdepth 1se non si vuole farlo funzionare in modo ricorsivo.

Un terzo e brillante modo IMO è spiegato da Steeldriver in questa risposta :

printf '%s\0' */ | xargs -0 rmdir

Questo utilizza l'integrato della shell printfper creare un elenco di argomenti delimitati da zero, questo elenco viene quindi reindirizzato a xargscui chiama rmdiresattamente tutte le volte che è necessario. Puoi farlo funzionare in modo ricorsivo con shopt -s globstare **/*/invece che */come sopra.


2
findè ricorsivo, ma il ciclo dell'OP non lo è. Per replicare quel comportamento, usa find -maxdepth 1 -type d -exec rmdir {} +. ( -depthè ridondante in quel caso.) Trucco pulito printfda emulare find -print0, non l'avevo mai visto prima.
Peter Cordes,

1
Oh! Ho visto il lse il whileciclo, mi mancava che erano reindirizzamento da un cambio di processo con findinvece di tubazioni lsnel circuito e proprio non mostrando per qualche ragione. Questo find *è davvero sepolto. Sì, è ricorsivo e fallirà se ci sono troppe voci di directory nella directory, incluse le non directory perché non vengono utilizzate */. find .sarebbe molto meglio, perché findè più veloce statnell'espansione globale di bash.
Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.