852 votes

Erreur de liste d'arguments trop longue pour les commandes rm, cp, mv

J'ai plusieurs centaines de PDF sous un répertoire sous UNIX. Les noms des PDF sont très longs (environ 60 caractères).

Lorsque j'essaie de supprimer tous les PDF ensemble en utilisant la commande suivante :

rm -f *.pdf

Je reçois l'erreur suivante :

/bin/rm: cannot execute [Argument list too long]

Quelle est la solution à cette erreur ? Cette erreur se produit-elle pour mv et cp ainsi que des commandes ? Si oui, comment résoudre ces commandes ?

29 votes

Vous pourriez trouver ceci lien utile

1 votes

Ceci peut également être pertinent http://mywiki.wooledge.org/BashFAQ/095

1190voto

Dennis Points 2232

La raison pour laquelle cela se produit est que bash étend l'astérisque à chaque fichier correspondant, ce qui produit une ligne de commande très longue.

Essayez ça :

find . -name "*.pdf" -print0 | xargs -0 rm

Attention : il s'agit d'une recherche récursive qui trouvera (et supprimera) également les fichiers dans les sous-répertoires. Ajoutez -f à la commande rm seulement si vous êtes sûr de ne pas vouloir de confirmation.

Vous pouvez faire ce qui suit pour rendre la commande non récurrente :

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm

Une autre option consiste à utiliser la fonction find -delete drapeau :

find . -name "*.pdf" -delete

1 votes

Cela n'envoie-t-il pas exactement les mêmes arguments à rm que rm -f *.pdf ? (Ou, s'il y a des sous-répertoires, encore plus d'arguments).

7 votes

Non, xargs divise spécifiquement la liste et émet plusieurs commandes si nécessaire.

0 votes

Notez que cette réponse, ainsi que l'autre réponse 'find', supprimera les fichiers PDF des sous-répertoires, ce qui est différent du comportement de 'rm *.pdf', bien que le comportement recherché par l'auteur de la question ne soit pas clair.

561voto

Édouard Lopez Points 2762

Tl;dr

C'est une limitation du noyau sur la taille de l'argument de la ligne de commande. Utilisez un for à la place.

Origine du problème

Il s'agit d'un problème système, lié à execve et ARG_MAX constante. Il existe une documentation abondante à ce sujet (voir l'homme exécute , Le wiki de Debian ).

Fondamentalement, l'expansion produit un commande (avec ses paramètres) qui dépasse la ARG_MAX limite. Sur le noyau 2.6.23 la limite a été fixée à 128 kB . Cette constante a été augmentée et vous pouvez obtenir sa valeur en l'exécutant :

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

Solution : Utiliser for Boucle

Utilisez un for comme il est recommandé sur BashFAQ/095 et il n'y a pas de limite, sauf pour la RAM/l'espace mémoire :

Faites un essai pour vous assurer qu'il supprimera ce que vous attendez :

for f in *.pdf; do echo rm "$f"; done

Et l'exécuter :

for f in *.pdf; do rm "$f"; done

Il s'agit également d'une approche portable car les glob ont un comportement fort et cohérent parmi les shells ( fait partie de la spécification POSIX ).

Note : Comme l'ont noté plusieurs commentaires, cette méthode est effectivement plus lente mais plus facile à maintenir car elle permet d'adapter des scénarios plus complexes, par exemple où l'on veut faire plus qu'une seule action.

Solution : Utiliser find

Si vous insistez, vous pouvez utiliser find mais vraiment n'utilisez pas xargs comme il "est dangereux (cassé, exploitable, etc.) lors de la lecture d'une entrée non délimitée par NUL". :

find . -maxdepth 1 -name '*.pdf' -delete 

Utilisation de -maxdepth 1 ... -delete au lieu de -exec rm {} + permet à find pour simplement exécuter lui-même les appels système requis sans utiliser de processus externe, donc plus rapidement (grâce à la fonction Commentaire de @chepner ).

Références

33 votes

Excellente réponse, c'est ainsi que l'on devrait répondre à toutes les questions sur les OS. Merci !

1 votes

+1 pour avoir mentionné le for boucle. J'ai utilisé find avant, mais je cherche toujours comment le faire car j'oublie tout le temps les options, etc. for semble plus facile à mémoriser IMHO

3 votes

Utilisé comme for f in *; do rm "$f"; done fonctionnent comme un charme

208voto

ThiefMaster Points 135805

find a un -delete action :

find . -maxdepth 1 -name '*.pdf' -delete

4 votes

Cela renvoie toujours le message "Argument list too long". En tout cas pour moi, c'est le cas. Utilisation de xargs selon la réponse de Dennis, fonctionne comme prévu.

7 votes

Cela ressemble à un bug dans find.

3 votes

@Sergio a eu le même problème, il a été causé par les guillemets manquants autour du modèle de nom.

15voto

Jon Lin Points 88615

Ou vous pouvez essayer :

find . -name '*.pdf' -exec rm -f {} \;

0 votes

Cela supprime également les fichiers des sous-répertoires. Comment éviter cela ?

0 votes

@NikunjChauhan Ajouter l'option -maxdepth : find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;

0 votes

Je ne parviens pas à insérer l'option maxdepth.

14voto

BigMike Points 3443

Vous pouvez essayer ceci :

for f in *.pdf
do
  rm "$f"
done

EDIT : Le commentaire de ThiefMaster me suggère de ne pas divulguer une pratique aussi dangereuse aux jeunes jedis du shell, donc je vais ajouter une version plus "sûre" (pour préserver les choses quand quelqu'un a un fichier "-rf . . .pdf")

echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
   echo "rm -i \"$f\""
done >> /tmp/dummy.sh

Après avoir exécuté le programme ci-dessus, il suffit d'ouvrir le /tmp/dummy.sh dans votre éditeur préféré et vérifiez chaque ligne pour les noms de fichiers dangereux, en les commentant s'ils sont trouvés.

Ensuite, copiez le dummy.sh script dans votre répertoire de travail et exécutez-le.

Tout cela pour des raisons de sécurité.

7 votes

Je pense que cela permettrait de faire des choses très intéressantes avec un fichier nommé par ex. -rf .. .pdf

0 votes

Oui, mais en général, lorsqu'elle est utilisée en shell, l'émetteur de la commande "devrait" jeter un coup d'oeil à ce qu'il fait :). En fait, je préfère rediriger vers un fichier et ensuite inspecter chaque ligne.

2 votes

Cela ne cite pas "$f". C'est ce dont parlait ThiefMaster. -rf a la priorité sur -i Votre deuxième version n'est donc pas meilleure (sans inspection manuelle). Et elle est fondamentalement inutile pour la suppression de masse, à cause de l'invite pour chaque fichier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X