J'ai plusieurs centaines de PDF sous un répertoire sous UNIX. Les noms des PDF sont vraiment longs (environ 60 caractères).
Lorsque j'essaie de supprimer tous les PDF ensemble à l'aide de la commande suivante:
rm -f *.pdf
J'obtiens l'erreur suivante:
/bin/rm: cannot execute [Argument list too long]
Quelle est la solution à cette erreur? Est -ce que cette erreur se produit pour mv
et des cp
commandes ainsi? Si oui, comment résoudre ces commandes?
Réponses:
La raison en est que bash étend réellement l'astérisque à chaque fichier correspondant, produisant une très longue ligne de commande.
Essaye ça:
Avertissement: il s'agit d'une recherche récursive qui trouvera (et supprimera) les fichiers dans les sous-répertoires également. N'utilisez
-f
la commande rm que si vous êtes sûr de ne pas vouloir de confirmation.Vous pouvez effectuer les opérations suivantes pour rendre la commande non récursive:
Une autre option consiste à utiliser l'
-delete
indicateur find :la source
xargs
divise spécifiquement la liste et émet plusieurs commandes si nécessaire.-maxdepth 1
doit être le premier argument après le chemin.-delete
indicateur pour supprimer les fichiers qu'il trouve, et même s'il ne le faisait pas, il serait toujours préférable d'utiliser-exec
pour exécuter rm, plutôt que d'appeler xargs (qui est maintenant 3 processus et un tube au lieu d'un seul processus avec-delete
ou 2 processus avec-exec
).dangerous (broken, exploitable, etc.)
, c'est assez ridicule. Vous devez sans aucun doute être prudent lors de l'utilisationxargs
, mais ce n'est pas tout à faiteval/evil
.-exec
appelrm
, le nombre de processus sera de 1 + nombre de fichiers, bien que le nombre de processus simultanés de celui-ci puisse être 2 (peut-être que find exécuterait les processus rm simultanément). Le nombre de processus utilisantxargs
serait considérablement réduit à 2 + n, où n est un certain nombre de processus inférieur au nombre de fichiers (disons le nombre de fichiers / 10, bien que cela dépende probablement plus de la longueur des chemins). En supposant que find effectue la suppression directement, using-delete
devrait être le seul processus à invoquer.tl; dr
C'est une limitation du noyau sur la taille de l'argument de ligne de commande. Utilisez
for
plutôt une boucle.Origine du problème
Il s'agit d'un problème système, lié
execve
etARG_MAX
constant. Il y a beaucoup de documentation à ce sujet (voir man execve , wiki de debian ).Fondamentalement, l'expansion produit une commande (avec ses paramètres) qui dépasse la
ARG_MAX
limite. Sur le noyau2.6.23
, la limite a été fixée à128 kB
. Cette constante a été augmentée et vous pouvez obtenir sa valeur en exécutant:Solution: utiliser la
for
boucleUtilisez une
for
boucle comme il est recommandé sur BashFAQ / 095 et il n'y a pas de limite sauf pour la RAM / espace mémoire:Un essai à sec pour vérifier qu'il supprimera ce que vous attendez:
Et exécutez-le:
C'est également une approche portable car les glob ont un comportement fort et cohérent entre les shells ( partie de la spécification POSIX ).
Remarque: Comme indiqué par plusieurs commentaires, cela est en effet plus lent mais plus facile à gérer car il peut adapter des scénarios plus complexes, par exemple lorsque l'on veut faire plus d'une seule action.
Solution: utilisation
find
Si vous insistez, vous pouvez utiliser
find
mais n'utilisez vraiment pas xargs car il "est dangereux (cassé, exploitable, etc.) lors de la lecture d'une entrée non délimitée par NUL" :Utiliser
-maxdepth 1 ... -delete
au lieu de-exec rm {} +
permetfind
d'exécuter simplement les appels système requis sans utiliser de processus externe, donc plus rapide (grâce au commentaire @chepner ).Références
la source
for
boucle. Je l'ai utiliséfind
auparavant, mais je cherche toujours comment le faire en oubliant les options, etc. tout le temps.for
semble plus facile à rappeler IMHOfor f in *; do rm "$f"; done
travail comme un charmefind -exec
solution semble être BEAUCOUP plus rapide que lafor
boucle.4.15.0-1019-gcp
pour être exact) et la limite est toujours à 2097152. Assez intéressant, la recherche d'ARG_MAX sur le repo linux git donne un résultat montrant que ARG_MAX est à 131702.find
a une-delete
action:la source
xargs
, selon la réponse de Dennis, fonctionne comme prévu.-exec
est de supprimer un tas de fichiers.-exec rm {} +
ferait la même chose, mais nécessite toujours de démarrer au moins un processus externe.-delete
permetfind
d'exécuter simplement les appels système requis sans utiliser de wrapper externe.Une autre réponse consiste à forcer
xargs
le traitement des commandes par lots. Par exemple pourdelete
les fichiers100
à la fois,cd
dans le répertoire et exécutez ceci:echo *.pdf | xargs -n 100 rm
la source
echo
trouve un shell intégré. Si vous finissez par utiliser la commandeecho
, vous rencontrerez toujours la limite des arguments du programme.Ou vous pouvez essayer:
la source
find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Si vous essayez de supprimer un très grand nombre de fichiers à la fois (j'ai supprimé un répertoire avec 485 000+ aujourd'hui), vous rencontrerez probablement cette erreur:
Le problème est que lorsque vous tapez quelque chose comme
rm -rf *
, le*
est remplacé par une liste de tous les fichiers correspondants, comme «rm -rf fichier1 fichier2 fichier3 fichier4» et ainsi de suite. Il y a un tampon de mémoire relativement petit alloué au stockage de cette liste d'arguments et s'il est rempli, le shell n'exécutera pas le programme.Pour contourner ce problème, beaucoup de gens utiliseront la commande find pour trouver chaque fichier et les passeront un par un à la commande "rm" comme ceci:
Mon problème est que j'avais besoin de supprimer 500 000 fichiers et cela prenait beaucoup trop de temps.
Je suis tombé sur un moyen beaucoup plus rapide de supprimer des fichiers - la commande "find" a un indicateur "-delete" intégré! Voici ce que j'ai fini par utiliser:
En utilisant cette méthode, je supprimais des fichiers à une vitesse d'environ 2000 fichiers / seconde - beaucoup plus rapidement!
Vous pouvez également afficher les noms de fichiers lorsque vous les supprimez:
… Ou même montrer combien de fichiers seront supprimés, puis le temps nécessaire pour les supprimer:
la source
sudo find . -type f -delete
pour supprimer environ 485 000 fichiers et cela a fonctionné pour moi. A pris environ 20 secondes.vous pouvez essayer ceci:
EDIT: Le commentaire de ThiefMaster me suggère de ne pas divulguer une telle pratique dangereuse aux jedis du jeune shell, donc j'ajouterai une version plus "plus sûre" (pour préserver les choses quand quelqu'un a un fichier "-rf. ..Pdf")
Après avoir exécuté ce qui précède, ouvrez simplement le fichier /tmp/dummy.sh dans votre fav. éditeur et vérifiez chaque ligne pour les noms de fichiers dangereux, en les commentant s'ils sont trouvés.
Copiez ensuite le script dummy.sh dans votre répertoire de travail et exécutez-le.
Tout cela pour des raisons de sécurité.
la source
-rf .. .pdf
-rf
a priorité sur-i
, donc votre 2ème version n'est pas meilleure (sans inspection manuelle). Et est fondamentalement inutile pour la suppression en masse, en raison de l'invite pour chaque fichier.Vous pouvez utiliser un tableau bash:
De cette façon, il sera effacé par lots de 1000 fichiers par étape.
la source
vous pouvez utiliser cette recommandation
la source
La commande rm a une limitation de fichiers que vous pouvez supprimer simultanément.
Vous pouvez les supprimer en utilisant plusieurs fois la commande rm en fonction de vos modèles de fichiers, comme:
Vous pouvez également les supprimer via la commande find :
la source
rm
n'a pas une telle limite sur le nombre de fichiers qu'il traitera (à part cela,argc
il ne peut pas être plus grand queINT_MAX
). C'est la limitation du noyau sur la taille maximale de l' ensemble du tableau d'arguments (c'est pourquoi la longueur des noms de fichiers est importante).S'il s'agit de noms de fichiers avec des espaces ou des caractères spéciaux, utilisez:
Cette phrase recherche tous les fichiers du répertoire courant (-maxdepth 1) avec l'extension pdf (-name '* .pdf'), puis supprime chacun (-exec rm "{}").
L'expression {} remplace le nom du fichier et "{}" définit le nom de fichier sous forme de chaîne, y compris les espaces ou les caractères spéciaux.
la source
-exec
est que vous n'invoquiez pas de shell. Les citations ici n'ont absolument rien d'utile. (Ils empêchent toute expansion générique et fractionnement de jetons sur la chaîne dans le shell où vous tapez cette commande, mais la chaîne{}
ne contient aucun espace blanc ni caractère générique shell.)j'étais confronté au même problème lors de la copie du répertoire source du formulaire vers la destination
le répertoire source avait des fichiers ~ 3 lakcs
j'ai utilisé cp avec l'option -r et cela a fonctionné pour moi
cp -r abc / def /
il copiera tous les fichiers de abc vers def sans avertir de la liste d'arguments trop longtemps
la source
Essayez aussi ceci Si vous voulez supprimer des fichiers / dossiers au-dessus de 30/90 jours (+) ou au-dessous de 30/90 jours (-), vous pouvez utiliser les commandes ex ci-dessous
Ex: pour 90 jours exclut ci-dessus après 90 jours de suppression de fichiers / dossiers, cela signifie 91,92 .... 100 jours
Ex: pour les derniers fichiers 30 jours que vous souhaitez supprimer, utilisez la commande ci-dessous (-)
Si vous voulez giz les fichiers depuis plus de 2 jours
Si vous ne souhaitez voir les fichiers / dossiers que depuis un mois. Ex:
Au-dessus de 30 jours de plus seulement, répertoriez les fichiers / dossiers Ex:
la source
Je suis surpris qu'il n'y ait pas de
ulimit
réponses ici. Chaque fois que j'ai ce problème, je me retrouve ici ou ici . Je comprends que cette solution a ses limites maisulimit -s 65536
semble souvent faire l'affaire pour moi.la source
J'ai eu le même problème avec un dossier plein d'images temporaires qui grandissait de jour en jour et cette commande m'a aidé à effacer le dossier
La différence avec les autres commandes est le paramètre mtime qui ne prendra que les fichiers antérieurs à X jours (dans l'exemple 50 jours)
En utilisant cela plusieurs fois, diminuant à chaque exécution de la plage de jours, j'ai pu supprimer tous les fichiers inutiles
la source
Je ne connais qu'un moyen de contourner cela. L'idée est d'exporter cette liste de fichiers pdf que vous avez dans un fichier. Ensuite, divisez ce fichier en plusieurs parties. Supprimez ensuite les fichiers pdf répertoriés dans chaque partie.
wc -l consiste à compter le nombre de lignes que contient list.txt. Lorsque vous avez une idée de sa durée, vous pouvez décider de la diviser en deux, en avant ou quelque chose comme ça. Utilisation de la commande split -l Par exemple, divisez-la en 600 lignes chacune.
cela créera quelques fichiers nommés xaa, xab, xac et ainsi de suite dépend de la façon dont vous le divisez. Maintenant, pour "importer" chaque liste de ces fichiers dans la commande rm, utilisez ceci:
Désolé pour mon mauvais anglais.
la source
pdf_format_sucks.docx
celui-ci sera également supprimé ... ;-) Vous devez utiliser une expression régulière correcte et précise lors de la recherche des fichiers pdf.still_pdf_format_sucks.docx
sera supprimé. Le point.
dans".pdf"
l'expression régulière correspond à n'importe quel caractère. Je suggérerais"[.]pdf$"
au lieu de.pdf
.J'ai rencontré ce problème plusieurs fois. De nombreuses solutions exécuteront la
rm
commande pour chaque fichier individuel qui doit être supprimé. C'est très inefficace:J'ai fini par écrire un script python pour supprimer les fichiers en fonction des 4 premiers caractères du nom de fichier:
Cela a très bien fonctionné pour moi. J'ai pu effacer plus de 2 millions de fichiers temporaires dans un dossier en environ 15 minutes. J'ai commenté le goudron du petit bout de code pour que toute personne ayant peu ou pas de connaissances en python puisse manipuler ce code.
la source
Et un autre:
printf
est un shell intégré, et pour autant que je sache, il en a toujours été ainsi. Maintenant que ceprintf
n'est pas une commande shell (mais une commande intégrée), elle n'est pas sujette àargument list too long ...
une erreur fatale.Nous pouvons donc l'utiliser en toute sécurité avec des modèles de globalisation du shell tels que
*.[Pp][Dd][Ff]
, puis nous dirigeons sa sortie vers larm
commande remove ( ), à traversxargs
, ce qui garantit qu'il tient suffisamment de noms de fichiers dans la ligne de commande afin de ne pas échouer larm
commande, qui est un shell commander.Le
\0
enprintf
sert un séparateur nul pour les noms de fichier dont sont ensuite traitées parxargs
commande, en l' utilisant (-0
) comme séparateur, doncrm
ne manque pas quand il y a des espaces blancs ou d' autres caractères spéciaux dans les noms de fichiers.la source
printf
ne s'agit pas d'un shell intégré, il sera soumis à la même limitation.Vous pouvez créer un dossier temporaire, déplacer tous les fichiers et sous-dossiers que vous souhaitez conserver dans le dossier temporaire, puis supprimer l'ancien dossier et renommer le dossier temporaire en l'ancien dossier, essayez cet exemple jusqu'à ce que vous soyez sûr de le faire en direct:
le
rm -r big_folder
supprimera tous les fichiers dansbig_folder
n'importe quel nombre. Vous devez juste être super prudent, vous devez d'abord avoir tous les fichiers / dossiers que vous souhaitez conserver, dans ce cas, c'étaitfile1.pdf
la source
Pour tout supprimer
*.pdf
dans un répertoire/path/to/dir_with_pdf_files/
Supprimer des fichiers spécifiques à l'
rsync
aide de caractères génériques est probablement la solution la plus rapide si vous avez des millions de fichiers. Et cela corrigera les erreurs que vous obtenez.(Étape facultative): DRY RUN. Pour vérifier ce qui sera supprimé sans le supprimer. "
. . .
Cliquez sur trucs et astuces rsync pour plus de hacks rsync
la source
J'ai trouvé que pour les listes de fichiers extrêmement volumineuses (> 1e6), ces réponses étaient trop lentes. Voici une solution utilisant le traitement parallèle en python. Je sais, je sais, ce n'est pas Linux ... mais rien d'autre n'a fonctionné ici.
(Cela m'a fait gagner des heures)
la source
J'ai rencontré un problème similaire lorsqu'il y avait des millions de fichiers journaux inutiles créés par une application qui remplissait tous les inodes. J'ai recouru à «localiser», j'ai obtenu tous les fichiers «localisés» d dans un fichier texte, puis les ai supprimés un par un. A pris du temps mais a fait le boulot!
la source
locate
réinstallé quand vous aviez encore de la place sur votre disque.Une version un peu plus sûre que l'utilisation de xargs, également non récursive:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
Filtrer nos répertoires ici est un peu inutile car 'rm' ne le supprimera pas de toute façon, et il peut être supprimé pour plus de simplicité, mais pourquoi exécuter quelque chose qui retournera définitivement une erreur?
la source
ls
est un antipattern commun qui devrait certainement être évité, et ajoute un certain nombre de bogues supplémentaires ici. Legrep | grep
n'est tout simplement pas très élégant.find
sont bonnes et bien documentées ici et ailleurs. Voir par exemple le mywiki.wooledge.org pour beaucoup plus sur ce sujet et les sujets connexes.Utiliser GNU parallel (
sudo apt install parallel
) est super facileIl exécute les commandes multithread où '{}' est l'argument passé
Par exemple
ls /tmp/myfiles* | parallel 'rm {}'
la source
ls
directement à d'autres commandes est un contre-modèle dangereux - cela, et le fait que l'expansion du caractère générique provoquera le même échec lors de l'exécutionls
comme expérimenté dans larm
commande d' origine .parallel
rend certaines personnes qui préfèrent éviter la complexité inconfortables - si vous regardez sous le capot, c'est assez opaque. Voir le fil de la liste de diffusion à lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html entre Stephane (l'un des grisbeards Unix et Linux StackExchange) et Ole Tange (l'auteur de Parallel).xargs -P
paralèle également, mais il le fait de manière plus simple et plus bête avec moins de pièces mobiles, ce qui rend son comportement beaucoup plus facile à prévoir et à raisonner.Pour supprimer les 100 premiers fichiers:
rm -rf 'ls | tête -100 '
la source
L'option ci-dessous semble simple à ce problème. J'ai obtenu cette information d'un autre fil, mais cela m'a aidé.
Exécutez simplement la commande ci-dessus et elle fera la tâche.
la source