J'ai quelques dossiers avec \n
caractère leurs noms.
par exemple:
$ ls
''$'\n''Test'
Cela fait référence à un dossier avec le nom du test et une ligne vide avant son nom.
Alors quand j’exécute 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 sur \n
et l'autre sur 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 que \nTest
n'est qu'un dossier?
Vous n'avez qu'une seule commande à cet endroit. Il est donc suffisant d'appeler find
avec -exec
flag appelant rmdir
:
find -depth -type d -exec rmdir {} \;
Ou utilisez l'option -delete
comme dans find -type d -delete
, mais cela ne fonctionnera pas avec des répertoires non vides. Pour cela, vous aurez également besoin du drapeau -empty
. Notez également que -delete
implique -depth
pour pouvoir être ignoré. Ainsi, une autre alternative viable qui conserve tout en un processus:
find -type d -empty -delete
Si le répertoire n'est pas vide, utilisez rm -rf {} \;
. Pour isoler uniquement les répertoires avec \n
dans le nom de fichier, nous pouvons combiner les commandes --- de bash citation ANSI-C$'...'
avec -name
:
find -type d -name $'*\n*' -empty -delete
POSIX-ly, nous pourrions le gérer de cette façon:
find -depth -type d -name "$(printf '*\n*' )" -exec rmdir {} \;
Il est à noter que si votre objectif est de supprimer des répertoires, alors -delete
est suffisant, cependant si vous voulez exécuter une commande sur directory, alors -exec
est le plus approprié.
Voir également
Vous pouvez utiliser des globes de shell au lieu de find
:
for d in */ ; do
rmdir "$d"
done
Shell glob */
correspond à tous les dossiers du répertoire en cours. Cette construction en boucle prend en charge le fractionnement correct de Word automatiquement.
Notez que selon les options de votre shell, cela peut ignorer les dossiers cachés (nom commençant par un.). 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 de toujours citer vos variables.
Les deux réponses écrites jusqu’à présent appellent rmdir
une fois par répertoire, mais comme rmdir
peut prendre plusieurs arguments, je me demande: n’y at-il pas un moyen plus efficace?
On pourrait simplement faire
rmdir */
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 de nombreux répertoires (voir Quel est le maximum longueur des arguments en ligne de commande dans gnome-terminal? ). Si vous souhaitez que cette approche fonctionne de manière récursive, activez l'option Shell globstar
avec shopt -s globstar
et utilisez **/*/
au lieu de */
.
Avec GNU find
(et si nous ne voulons pas simplement utiliser -delete
), nous pourrions faire
find -depth -type d -exec rmdir {} +
ce qui construit la ligne de commande "de la même manière que xargs
construit ses lignes de commande" (man find
). Remplacez -depth
par -maxdepth 1
si vous ne voulez pas que cela fonctionne de manière récursive.
Un troisième et brillant moyen IMO est expliqué par steeldriver dans cette réponse :
printf '%s\0' */ | xargs -0 rmdir
Ceci utilise le shell intégré printf
pour construire une liste d'arguments délimitée par des zéros. Cette liste est ensuite redirigée vers xargs
qui appelle rmdir
aussi souvent que nécessaire. Vous pouvez le faire fonctionner de manière récursive avec shopt -s globstar
et **/*/
au lieu de */
comme ci-dessus.