Quelque chose que je sens que je dois savoir à coup sûr: si je ls <something>
, vais rm <something>
supprimer exactement les mêmes fichiers ls
affichés? Existe-t-il des circonstances dans lesquelles des rm
fichiers non visibles pourraient être supprimés ls
? (Ceci est dans le 18.04 bash)
Edit: merci à tous ceux qui ont répondu. Je pense que la réponse complète est une combinaison de toutes les réponses, aussi j’ai accepté la réponse la plus votée comme "la réponse".
Des choses inattendues que j'ai apprises en cours de route:
ls
n'est pas aussi simple qu'on pourrait le penser dans le traitement de ses arguments- Dans une simple installation sans fioritures d’Ubuntu, alias .bashrc
ls
- Ne nommez pas vos fichiers en commençant par un tiret, car ils peuvent ressembler à des arguments de commande. Nommer one -r le demande!
rm
ne pas avoir de--dry-run
drapeau ...find -delete
mieux querm
? Vous dites "Voilà pourquoi" , mais je ne vois absolument pas ce que cela signifie. Notez également que votrefind
invocation supprimera tous les fichiers de manière récursive dans le répertoire actuel, oùrm
ils supprimeront simplement les fichiers du répertoire immédiat. Aussi-name *
est un no-op. Dans l’ensemble, votre conseilfind
est parce que vous pouvez l'exécuter, voir tous les fichiers, puis exécuter la même commande avec-delete
. Puisque vous avez déjà vu les résultatsfind
, il ne devrait y avoir aucune ambiguïté quant à ce qui sera supprimé (j'aimerais en savoir plus à ce sujet sous la forme d'une réponse)-delete
" - Mais comment cela vaut-il mieux que d'exécuterls <filespec>
, suivi derm <filespec>
(ce que l'OP sait déjà faire)?find ... -print
abord pour vérifier quels fichiers seront supprimésfind ... -delete
, vous supprimerez tout de même les fichiers créés entre les deux commandes. Si vous utilisez les deux-print
et-delete
, vous n'obtenez pas de confirmation, mais simplement un rapport a posteriori de ce qui a été supprimé (et vous pourriez aussi bien l'utiliserrm -v
).Réponses:
Eh bien, à la fois
ls
etrm
fonctionner sur les arguments qui sont passés à eux.Ces arguments peuvent être un fichier simple, si
ls file.ext
etrm file.ext
fonctionnent sur le même fichier et le résultat est clair (liste le fichier / supprimer le fichier).Si , au contraire l' argument est un répertoire,
ls directory
liste le contenu du répertoire toutrm directory
ne fonctionne pas comme est -à- dire (rm
sans drapeaux ne peuvent pas supprimer des répertoires, alors que si vous le faitesrm -r directory
, il supprime récursive tous les fichiers sousdirectory
et le répertoire lui - même ).Mais gardez à l'esprit que les arguments de ligne de commande peuvent être soumis à une expansion du shell , il n'est donc pas toujours garanti que les mêmes arguments soient transmis aux deux commandes s'ils contiennent des caractères génériques, des variables, des sorties d'autres commandes, etc.
Comme exemple extrême, pensez
ls $(rand).txt
etrm $(rand).txt
les arguments sont "les mêmes" mais les résultats sont très différents!la source
ls
vsrm *
où il y a des fichiers "cachés" (point), même si ce n'est pas du tout une comparaison juste, car je n'ai pas écritls *
. Mais celarm
n'a pas de sens en lui-même, de sorte que tout est en réalité des pommes et des oranges. Si j'ai bien compris, c'est le coeur de votre réponse, alors bon travail :)ls
vsrm -r
: la commandels <directory>
ne sera pas afficher les fichiers cachés à l' intérieur du répertoire, maisrm -r <directory>
va supprimer même les fichiers cachés.ls
ne les listera pas (sauf s'il est associé à un aliasls -a
), etrm *
ne les supprimera pas (à moins que vous ne l'ayezdotglob
défini).Si vous pensez à quelque chose comme
ls foo*.txt
vsrm foo*.txt
, alors oui, ils afficheront et supprimeront les mêmes fichiers. Le shell développe le glob et le passe à la commande en question. Les commandes fonctionnent sur les fichiers listés. On les énumère, on les enlève.La différence évidente est que si l'un de ces fichiers se trouvait être un répertoire,
ls
son contenu serait répertorié, maisrm
il ne parviendrait pas à le supprimer. Ce n'est généralement pas un problème, carrm
supprimerait moins que ce qui a été montré parls
.Le gros problème vient de la course
ls *
ourm *
dans un répertoire contenant des noms de fichiers commençant par un tiret . Ils s’étendraient aux lignes de commande des deux programmes comme si vous les écriviez vous-même, etls
voulaient-r
dire «ordre de tri inversé», alorsrm
qu’il faudrait-r
un retrait récursif. La différence est importante si vous avez des sous-répertoires d’au moins deux niveaux. (ls *
montrera le contenu des répertoires de premier niveau, maisrm -r *
tout dépassera également le premier niveau.)Pour éviter cela, écrivez des variables globales permissives avec un interligne
./
pour indiquer le répertoire actuel et / ou mettez une--
pour signaler la fin du traitement des options avant la variable globale (c'estrm ./*
-à- dire ourm -- *
).Avec un glob comme
*.txt
, cela n’est en réalité pas un problème, car le point est un caractère d’option non valide et provoquera une erreur (jusqu’à ce que les utilitaires développent leur utilité pour en inventer un sens), mais il est toujours plus sûr de le mettre de./
toute façon.Bien sûr, vous pouvez également obtenir des résultats différents pour les deux commandes si vous modifiez les options de déplacement du shell ou les fichiers créés / déplacés / supprimés entre les commandes, mais je doute que vous ayez pensé à l'un ou l'autre de ces cas. (Traiter avec des fichiers nouveaux / déplacés serait extrêmement compliqué à faire en toute sécurité.)
la source
Laissant de côté le comportement de la coquille, concentrons-nous uniquement sur ce
rm
que nousls
pouvons gérer nous-mêmes. Au moins un cas dans lequells
montrera ce quirm
ne peut pas être supprimé implique des autorisations de répertoire, et l'autre - des répertoires spéciaux.
et..
.Autorisations de dossier
rm
est une opération sur un répertoire, car en supprimant un fichier, vous modifiez le contenu du répertoire (ou en d’autres termes, la liste des entrées de répertoire, car le répertoire n’est rien de plus qu’une liste de noms de fichiers et d’inodes ). Cela signifie que vous avez besoin d'autorisations d'écriture sur un répertoire. Même si vous êtes le propriétaire du fichier , sans autorisations de répertoire, vous ne pouvez pas supprimer de fichiers. L' inverse est également vrai : vousrm
pouvez supprimer les fichiers pouvant appartenir à d'autres personnes, si vous êtes propriétaire du répertoire.Ainsi, vous pouvez très bien avoir lu et exécuté des autorisations sur un répertoire, ce qui vous permettra de parcourir le répertoire et d'afficher son contenu sans problème, par exemple
ls /bin/echo
, mais vous ne pouvez pas le faire àrm /bin/echo
moins d'être propriétaire/bin
ou d'élever vos privilègessudo
.Et vous verrez des cas comme celui-ci partout. Voici un exemple: https://superuser.com/a/331124/418028
Annuaires spéciaux '.' et '..'
Un autre cas particulier est
.
et..
répertoires. Si vous le faitesls .
ouls ..
, il vous montrera avec plaisir le contenu, mais ilrm
n'est pas autorisé de le faire:la source
Si vous tapez
ls *
et puisrm *
, il est possible que vous supprimiez plus de fichiers que ceuxls
indiqués - ils ont peut-être été créés dans un intervalle de temps très court entre la finls
et le début derm
.la source
/tmp
lequel de nombreuses applications peuvent créer des fichiers temporaires. C'est donc toujours une possibilité dans les deux commandes*
. Cependant, certaines applications rendent également les fichiers anonymes enunlink()
les gardant tout en gardant le descripteur de fichier ouvert. Il est donc possible qu’il apparaisse dans le fichier,ls *
maisrm *
ne le détecte pas.*
s'il existe une différence entre ce quils
serait affiché et ce quirm
fonctionne, car la liste du contenu des répertoires a changé entre les deux.ls *
pourrait en fait afficher le nom de fichier qui a déjà disparu.ls *
etrm *
ne sont pas responsables de l'expansion du glob - cela est fait par le shell avant de le passer à la commande.Cela signifie que vous pouvez utiliser n’importe quelle commande avec la liste de fichiers étendue. Par conséquent, j’utiliserai quelque chose qui fait le moins possible.
Donc, une meilleure façon de faire cela (ou du moins une autre façon) est de sauter l’intermédiaire.
echo *
va vous montrer exactement ce qui serait passé à votrerm
commande.la source
printf "%s\n" *
pour obtenir une vue non ambiguë sur les noms de fichiers avec des espaces. (Ou%q
au lieu de gérer les sauts de ligne et les caractères de contrôle aussi, au détriment d'une sortie plus laide.)Que diriez-vous:
Fondamentalement, les caractères génériques étendus à des éléments commençant par
-
(ou des éléments entrés manuellement commençant par-
mais qui ressemblent un peu plus à de la triche) peuvent être interprétés différemment parls
etrm
.la source
Il y a des cas extrêmes où ce qui
ls
est montré n'est pas ce qui estrm
éliminé. Un cas extrême, mais heureusement bénin, est si l'argument que vous passez est un lien symbolique vers un répertoire:ls
vous montrera tous les fichiers du répertoire contenant un lien symbolique , toutrm
en supprimant le lien symbolique, en laissant le répertoire original et son contenu intacts:la source
ln -s $HOME some_link; ls some_link
sortiessome_link@
pour moi, mais je ails
aliasé àls -F
. Apparemment,-F
modifie le comportement pour afficher le lien au lieu de le déréférencer. Je ne m'attendais pas à ça.ls -l
par exemple, cible le lien, pas la destination ... il doit y avoir des moyens d'inspecter le lien lui-même.ls
etrm
.ls some_link/
,ls -H some_link
ouls -L some_link
, le répertoire lié sera répertorié, même si vous ajoutez-F
ou-l
. Réciproquement (en quelque sorte),-d
dit de regarder un répertoire plutôt que son contenu; comparerls -l /tmp
etls -ld /tmp
.ls
. En gros, vous montrez pourquoi énumérer des comportements avec différents drapeaux ne vaut pas la peine de poser cette question ...Si vous ne le faites qu'à la
ls
place dels -a
, ouirm
peut supprimer les fichiers cachés que vous n'avez pas vusls
sans-a
.Exemple :
Selon :
ls dir_test
: affichera seulement test2ls -A dir_test
: affichera test2 + .testrm -r dir_test
: va supprimer tout (.test + test2)J'espère que cela vous aidera.
la source
rm *
ne supprimera pas les fichiers de points. Si c'est le cas,ls *
leur montrera également.ls *
ne pas afficher les fichiers cachés.ls -a
listera.
,..
,.test
ettest2
. Vous voudrez peut-être changer votre exemple à utiliserls -A
, qui répertorie tout sauf sauf.
et..
(c'est-à-dire seulement.test
ettest2
).Il y a déjà beaucoup de bonnes réponses, mais je veux ajouter un aperçu plus profond.
Posez-vous la question: combien de paramètres sont passés à
ls
, si vous écrivez...? Notez que la
ls
commande n'obtient pas le*
paramètre as s'il existe des fichiers*
pouvant être développés. Au lieu de cela, le shell commence par effectuer une analyse de globalisation avant d'appeler la commande. Cettels
commande obtient donc autant de paramètres qu'il y a de fichiers correspondant à cette analyse. Pour supprimer la suppression, citez le paramètre.Cela est vrai pour toute commande:
echo *
vsecho '*'
.Il existe un script, appelez-le
countparams.sh
pour tester l'effet. Il vous indique le nombre de paramètres passés et les répertorie.Rendez-le exécutable et courez
./countparams.sh *
. Apprenez de sa sortie!la source
Le glob se développera de la même manière les deux fois, si le contenu du répertoire est le même à ces deux moments différents.
Si vous voulez vraiment vérifier ce qui sera supprimé, utilisez
rm -i *.txt
. Il vous demandera séparément pour chaque fichier avant de (essayer de) le supprimer.Ceci est garanti contre les conditions de concurrence:
ls *.txt
/ un nouveau fichier est créé /rm *.txt
parce que chaque fichier est invité par le même programme que celui qui effectue la suppression.
Ceci est trop lourd pour une utilisation normale, et si vous alias
rm
pourrm -i
, vous vous retrouverez en utilisant\rm
ourm -f
assez souvent. Mais il convient au moins de mentionner qu’il existe une solution à la situation de concurrence critique. (Il est même portable sur des systèmes non-GNU: POSIXrm(1)
spécifie l'-i
option .)Une autre option serait un tableau bash:,
to_remove=(*.txt)
puis demandez à l'utilisateur de confirmer (peut-être aprèsls -ld -- "${to_remove[@]}"
), puisrm -- "${to_remove[@]}"
. Ainsi, l’expansion globale n’est effectuée qu’une fois et la liste est transmise textuellementrm
.Une autre option pratiquement utilisable est GNU
rm -I
( page de manuel ), qui vous invite si vous supprimez plus de 4 éléments. (Mais ne vous montre pas la liste, mais le total.) J'utilisealias rm='rm -I'
sur mon bureau.C'est une bonne protection contre le retour du gros doigt avec un motif à moitié tapé qui correspond trop. Mais utiliser en
ls
premier est généralement bon dans un répertoire que vous possédez ou sur un système mono-utilisateur, et lorsqu'il n'y a pas de processus en arrière-plan qui pourrait y créer de manière asynchrone de nouveaux fichiers. Pour éviter les gros doigtés, ne tapez pasrm -rf /foo/bar/baz
de gauche à droite.rm -rf /
est spécial, maisrm -rf /usr
ne l'est pas! Laissez la-rf
partie ou commencez avec ellels
et ajoutez-la seulementrm -rf
après avoir tapé le chemin.la source