Je me demandais si l'utilisation rm $(ls)
pour supprimer des fichiers (ou rm -r $(ls)
pour supprimer des répertoires également) était sûre? Parce que dans tous les sites Web, les gens donnent d'autres moyens de le faire, même si cette commande semble beaucoup plus facile que d'autres commandes.
13
touch 'foo -r .. bar'
;rm $(ls)
; où est passé mon répertoire parent? De plus, quel genre d'alternatives voyez-vous qui sont encore plus compliquées que cela?rm *
est beaucoup plus facile à taper et à penser, et plus sûr (mais pas parfaitement sûr; voir la réponse de Dennis).ls
peut varier d'une implémentation à l'autre et n'est donc pas standard. En fonction de vos besoins, envisagez des alternatives telles quefind
etstat
. Vous ne devez l'utiliserls
que pour la consommation humaine, jamais pour une utilisation par d'autres commandes ou dans des scripts.Réponses:
Qu'est-ce que cela est destiné à faire?
ls
liste les fichiers dans le répertoire courant$(ls)
substitue la sortie desls
lieux comme argument pourrm
rm $(ls)
Est essentiellement destiné à supprimer tous les fichiers du répertoire actuelQu'est-ce qui ne va pas avec cette image ?
ls
ne peut pas gérer correctement les caractères spéciaux dans le nom de fichier. Les utilisateurs d'Unix conseillent généralement d'utiliser différentes approches . J'ai également montré cela dans une question connexe sur le comptage des noms de fichiers . Par exemple:En outre, comme il est correctement mentionné dans la réponse de Denis, un nom de fichier avec des tirets de tête peut être interprété comme un argument
rm
après substitution, ce qui va à l'encontre de l'objectif de suppression du nom de fichier.Ce qui fonctionne
Vous souhaitez supprimer des fichiers dans le répertoire actuel. Utilisez donc glob
rm *
:Vous pouvez utiliser la
find
commande. Cet outil est fréquemment recommandé pour plus que le répertoire actuel - il peut parcourir récursivement toute l'arborescence de répertoires et fonctionner sur des fichiers via-exec . . .{} \;
Python n'a pas de problème avec les caractères spéciaux dans les noms de fichiers, nous pourrions donc également l'utiliser (notez que celui-ci est uniquement pour les fichiers, vous devrez l'utiliser
os.rmdir()
etos.path.isdir()
si vous souhaitez opérer sur des répertoires):En fait, la commande ci-dessus pourrait être transformée en fonction ou en alias
~/.bashrc
par souci de concision. Par exemple,La version Perl de ce serait
la source
"$(ls)"
exemple ne fonctionne que s'il n'y a qu'un seul fichier dans le répertoire. Vous pourriez tout aussi bien utiliser la complétion de tabulation pour développer le nom de fichier car c'est la seule complétion.ls
alors :) Je vais le modifier$(ls)
pour désactiver le fractionnement de mots, soit vous laissez le fractionnement de mots se produire (avec des résultats désastreux). Le seul moyen propre de contourner une liste de plusieurs chaînes sans traiter les données comme du code est avec des variables de tableau ou avec\0
un séparateur, mais le shell lui-même ne peut pas le faire. C'est toujoursIFS=$'\n'
le moins dangereux, mais ne peut pas correspondrefind -print0 | xargs -0
. Ougrep -l --null
. Ou vous évitez tout le problème avec des choses commefind -exec rm {} +
. (Notez le+
pour passer plusieurs arguments à chaque invocation de rm; WAY more efficient).IFS=$'\n'
échouera également dans ce cas, car j'ai un retour à la ligne dans le nom de fichier, donc le découpage de mots le traitera comme deux noms de fichiers au lieu d'un. La raison étrange, cependant, est le fait qu'avec la valeur par défautIFS
qui est l'espace, la tabulation, la nouvelle ligne, l'originalrm "$(ls)"
devrait également échouer, il devrait traiter comme je l'ai dit le nom de fichier comme deux noms distincts, mais ce n'est pas le cas. En règle générale, j'utilisefind
avec-exec
, ou unefind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
structure pour gérer les noms de fichiers. Ou on pourrait utiliserpython
, j'ai ajouté un exemple de cela."$(ls)"
s'étend toujours à un argument, car les guillemets protègent l'expansion de la$(ls)
séparation des mots. Tout comme ils protègent"$foo"
.Non, ce n'est pas sûr, et l'alternative couramment utilisée
rm *
n'est pas beaucoup plus sûre.Il y a beaucoup de problèmes avec
rm $(ls)
. Comme d'autres l'ont déjà couvert dans leurs réponses, la sortie dels
sera divisée en caractères présents dans le séparateur de champ interne .Dans le meilleur des cas, cela ne fonctionne tout simplement pas. Dans le pire des cas, vous vouliez supprimer uniquement les fichiers (mais pas les répertoires) - ou supprimer sélectivement certains fichiers avec
-i
- mais il y a un fichier avec le nomc -rf
dans le répertoire actuel. Voyons ce qui se passe.La commande
rm -i $(ls)
était censée supprimer uniquement les fichiers et demander avant de supprimer chacun d'eux, mais la commande qui a finalement été exécutée était en lectureil a donc fait autre chose entièrement.
Notez que ce
rm *
n'est que légèrement mieux. Avec la structure du répertoire comme précédemment, il se comportera comme prévu ici, mais si vous avez un fichier appelé-rf
, vous n'avez toujours pas de chance.Il existe plusieurs meilleures alternatives. Les plus simples n'impliquent que rm et globbing.
La commande
fonctionnera exactement comme prévu, où
--
signale que tout ce qui suit ne doit pas être interprété comme une option.Cela fait partie des directives de syntaxe de l'utilitaire POSIX depuis plus de deux décennies maintenant. Il est répandu, mais il ne faut pas s'attendre à ce qu'il soit présent partout.
La commande
rend le glob se développer différemment et ne nécessite donc aucun support de l'utilitaire appelé.
Pour mon exemple ci-dessus, vous pouvez voir la commande qui sera finalement exécutée en ajoutant l' écho .
Le caractère principal
./
empêche rm de traiter accidentellement les noms de fichiers comme des options.la source
rm
. +1touch 'foo -rf .. bar
. Je ne pense pas qu'un attaquant puisse obtenir plus haut que le répertoire parent, à moins que nous ne puissions produire un séparateur de chemin dansls
la sortie de.rm: refusing to remove '.' or '..' directory: skipping '..'
ou quelque chose de similaire lorsque vous essayez de supprimer le répertoire parent.