J'ai quelques dossiers avec du \n
caractère dans leurs noms.
par exemple:
$ ls
''$'\n''Test'
Cela fait référence à un dossier avec le nom du test et une ligne vide devant son nom.
Donc, quand je lance des scripts comme celui-ci, dans son répertoire parent:
while IFS= read -r d; do
rmdir $d
done < <(find * -type d)
Ça montre:
rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Parce qu'il s'exécute deux fois, une fois \n
et l'autre Test
, car le nom du dossier a deux lignes.
Alors, comment puis-je résoudre ce problème de telle sorte que le script sache qu'il ne \nTest
s'agit que d'un dossier?
command-line
bash
scripts
Tara S Volpe
la source
la source
-print0
directive find et l'-d
option read. Voir stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done
commande a cette sortiermdir: failed to remove 'Test': No such file or directory
.rmdir "$file"
Réponses:
Vous n'avez qu'une seule commande là-bas, il suffit donc d'appeler
find
avec l'-exec
indicateur d'appelrmdir
:Ou utilisez l'
-delete
option comme dansfind -type d -delete
, mais elle ne fonctionnera pas avec les répertoires non vides. Pour cela, vous aurez également besoin d'un-empty
drapeau. Notez également,-delete
implique-depth
que cela peut être ignoré. Ainsi une autre alternative viable qui garde tout comme un seul processus:Si le répertoire n'est pas vide, utilisez
rm -rf {} \;
. Pour isoler uniquement les répertoires avec le\n
nom de fichier, nous pouvons combiner la citation ANSI-C$'...'
de-name
bash avec l' option:POSIX-ly, nous pourrions le gérer de cette façon:
Il convient de mentionner que si votre objectif est la suppression des répertoires, cela
-delete
suffit, mais si vous souhaitez exécuter une commande sur le répertoire,-exec
c'est le plus approprié.Voir également
find
sortie?la source
rm -rf
avec précaution . ; P N'a pasfind
d'-delete
option btw? Il supprime les répertoires vides et renvoie des erreurs pour les répertoires non vides commermdir
- pourrait être moins cher.-delete
ne supprimera pas les répertoires non vides. Par conséquent, l' utilisation prudente derm -rf
find
commandes sans aucune charge utile destructrice (c.-à-d. Supprimez le-delete
ou-exec whatever \;
) pour vérifier si la liste des fichiers affectés est réellement correcte et ne contient pas des éléments qui ne devraient pas être supprimés ...find
. Utilisez-exec rmdir {} +
pour regrouper plusieurs arguments sur une seulermdir
ligne de commande. Et BTW " mais cela ne fonctionnera pas avec les répertoires non vides. " S'appliquermdir
également, donc ce n'est pas vraiment une différence avec-delete
. C'est une différencerm -r
.find -type d -empty -delete
(-delete
implique-depth
).Vous pouvez utiliser des globes shell au lieu de
find
:Le shell glob
*/
correspond à tous les dossiers du répertoire actuel. Cette construction pour boucle assure automatiquement la séparation correcte des mots.Notez que selon vos options de shell, cela peut ignorer les dossiers cachés (nom commençant par a.). Ce comportement peut être modifié pour correspondre à tous les fichiers de la session en cours à l'aide de la commande
shopt -s dotglob
.N'oubliez pas non plus de toujours citer vos variables.
la source
find
faitshopt -s globstar
et en utilisant un**/*/
glob à la place.Les deux réponses écrites jusqu'ici appellent
rmdir
une fois par répertoire, mais commermdir
peuvent prendre plusieurs arguments, je me demande: n'y a-t-il pas un moyen plus efficace?On pourrait simplement faire
et c'est certainement le moyen le plus simple et le plus efficace, mais cela peut générer une erreur dans le cas de nombreux répertoires (voir Quelle est la longueur maximale des arguments de ligne de commande dans gnome-terminal? ). Si vous souhaitez que cette approche fonctionne récursivement, activez l'
globstar
option shell avecshopt -s globstar
et utilisez à la**/*/
place de*/
.Avec GNU
find
(et si nous ne voulons pas simplement utiliser-delete
), nous pourrions fairequi construit la ligne de commande "de la même manière que celle qui
xargs
construit ses lignes de commande" (man find
). Remplacez-depth
-le-maxdepth 1
si vous ne voulez pas qu'il fonctionne récursivement.Un troisième moyen brillant de l'OMI est expliqué par Steeldriver dans cette réponse :
Cela utilise le shell intégré
printf
pour construire une liste d'arguments délimitée par zéro, cette liste est ensuite dirigée versxargs
laquelle appellermdir
exactement aussi souvent que nécessaire. Vous pouvez le faire fonctionner récursivement avecshopt -s globstar
et**/*/
au lieu de*/
comme ci-dessus.la source
find
est récursif, mais pas la boucle de l'OP. Pour reproduire ce comportement, utilisezfind -maxdepth 1 -type d -exec rmdir {} +
. (-depth
est redondant dans ce cas.) Astuce intéressanteprintf
pour émulerfind -print0
, je n'avais jamais vu ça auparavant.ls
et lawhile
boucle, j'ai raté qu'ils redirigeaient à partir d'une substitution de processus avecfind
au lieu de canaliserls
dans la boucle et ne le montraient pas pour une raison quelconque. C'estfind *
vraiment enterré. Oui, il est récursif et échouera s'il y a trop d'entrées de répertoire dans le répertoire, y compris des non-répertoires car il n'utilise pas*/
.find .
serait beaucoup mieux, car ilfind
est plus rapide àstat
ing que l'expansion globale de bash.