J'ai un dossier avec plus d'un million de fichiers qui doit être trié, mais je ne peux rien faire car mv
ce message est affiché tout le temps.
-bash: /bin/mv: Argument list too long
J'utilise cette commande pour déplacer des fichiers sans extension:
mv -- !(*.jpg|*.png|*.bmp) targetdir/
Réponses:
xargs
est l'outil pour le travail. Que, oufind
avec-exec … {} +
. Ces outils exécutent une commande plusieurs fois, avec autant d'arguments que possible en une fois.Les deux méthodes sont plus faciles à exécuter lorsque la liste des arguments variables est à la fin, ce qui n'est pas le cas ici: l'argument final
mv
est la destination. Avec les utilitaires GNU (c’est-à-dire sur Linux non intégré ou Cygwin), l’-t
option tomv
est utile, pour transmettre la destination en premier.Si les noms de fichier ne comportent ni espace ni espace
\"'
, vous pouvez simplement fournir les noms de fichier comme entréexargs
(laecho
commande est une commande intégrée de bash, elle n'est donc pas soumise à la limite de longueur de ligne de commande):Vous pouvez utiliser l'
-0
option pourxargs
utiliser une entrée délimitée par des valeurs NULL au lieu du format cité par défaut.Alternativement, vous pouvez générer la liste des noms de fichiers avec
find
. Pour éviter de rentrer dans les sous-répertoires, utilisez-type d -prune
. Etant donné qu'aucune action n'est spécifiée pour les fichiers image répertoriés, seuls les autres fichiers sont déplacés.(Cela inclut les fichiers de points, contrairement aux méthodes génériques du shell.)
Si vous n'avez pas d'utilitaire GNU, vous pouvez utiliser un shell intermédiaire pour obtenir les arguments dans le bon ordre. Cette méthode fonctionne sur tous les systèmes POSIX.
Dans zsh, vous pouvez charger le
mv
paquet intégré :ou si vous préférez laisser
mv
et d'autres noms continuer à faire référence aux commandes externes:ou avec des globs de style ksh:
Sinon, utilisez GNU
mv
etzargs
:la source
shopt -s extglob
activer. J'avais raté une étape dans lesfind
commandes, je les ai corrigées.find
commandes que j'ai postées (maintenant) fonctionnent. Vous devez avoir omis une partie lors du copier-coller.!
? C’est plus explicite et plus facile à comprendre que l’étrange fuite-o
. Par exemple,! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
Si travailler avec le noyau Linux est suffisant, vous pouvez simplement faire
cela fonctionnera car le noyau Linux a inclus un correctif il y a environ 10 ans qui modifiait la limite d'arguments pour qu'elle soit basée sur la taille de la pile: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit /? id = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
Mise à jour: Si vous vous sentez courageux, vous pouvez dire
et toutes les extensions de shell vous conviendront aussi longtemps que vous aurez assez de RAM.
la source
ulimit -s unlimited
et cela fonctionnera pour des fichiers pratiquement illimités.ulimit -s unlimited
limite de ligne de commande réelle est de 2 ^ 31 ou 2 Go. (MAX_ARG_STRLEN
source du noyau.)La limite de dépassement d'argument du système d'exploitation ne s'applique pas aux extensions qui se produisent dans l'interpréteur de shell. Donc, en plus d'utiliser
xargs
oufind
, nous pouvons simplement utiliser une boucle shell pour décomposer le traitement enmv
commandes individuelles :Ceci utilise uniquement les fonctionnalités et les utilitaires POSIX Shell Command Language. Cette ligne est plus claire avec l'indentation, avec les points-virgules inutiles supprimés:
la source
mv
processus, au lieu des quelques nécessaires à l'aide de lafind
solution POSIX @Gilles affichée. En d'autres termes, cette méthode génère beaucoup de temps processeur inutile.case
instruction sur le résultat de l'*
extension permettant de filtrer plusieurs extensions est équivalente à l'!(*.jpg|*.png|*.bmp)
expression d' origine . Lafind
réponse n’est en fait pas équivalente; il descend dans les sous-répertoires (je ne vois pas de-maxdepth
prédicat).-name . -o -type d -prune -o
protège de la descente dans les sous-répertoires.-maxdepth
n'est apparemment pas conforme à POSIX, bien que ce ne soit pas mentionné dans mafind
page de manuel.Pour une solution plus agressive que celles proposées précédemment, extrayez votre source de noyau et éditez
include/linux/binfmts.h
Augmentez la taille de
MAX_ARG_PAGES
quelque chose de plus grand que 32. Cela augmente la quantité de mémoire que le noyau autorisera pour les arguments du programme, vous permettant ainsi de spécifier votre commandemv
ourm
pour un million de fichiers ou quoi que vous fassiez. Recompiler, installer, redémarrer.IL FAUT SE MÉFIER! Si vous définissez une taille trop grande pour la mémoire de votre système, exécutez une commande contenant de nombreux arguments Soyez extrêmement prudent lorsque vous utilisez des systèmes multi-utilisateurs, cela permettra aux utilisateurs malveillants d'utiliser plus facilement toute votre mémoire!
Si vous ne savez pas comment recompiler et réinstaller votre noyau manuellement, il est probablement préférable de prétendre que cette réponse n'existe pas pour le moment.
la source
Une solution plus simple utilisant à la
"$origin"/!(*.jpg|*.png|*.bmp)
place d'un bloc catch:Merci à @Score_Under
Pour un script multiligne, vous pouvez effectuer les opérations suivantes (notez ce qui
;
précède avant que ledone
message ne soit supprimé):Pour faire une solution plus généralisée qui déplace tous les fichiers, vous pouvez faire le one-liner:
Ce qui ressemble à ceci si vous faites une indentation:
Cela prend chaque fichier de l’origine et les déplace un par un vers la destination. Les guillemets
$file
sont nécessaires au cas où des noms de fichiers contiennent des espaces ou d’autres caractères spéciaux.Voici un exemple de cette méthode qui a parfaitement fonctionné
la source
!(*.jpg|*.png|*.bmp)
. Vous pouvez ajouter cela à votre boucle for-line en effectuant une suppression"$origin"/!(*.jpg|*.png|*.bmp)
pour éviter le recours au commutateur utilisé dans la réponse de Kaz et conserver le corps simple de la boucle-for.Parfois, il est plus simple d'écrire un petit script, par exemple en Python:
la source
Vous pouvez contourner cette restriction tout en continuant à l'utiliser
mv
si cela ne vous dérange pas de l'exécuter plusieurs fois.Vous pouvez déplacer des portions à la fois. Disons par exemple que vous avez une longue liste de noms de fichiers alphanumériques.
Ça marche. Puis assommer un autre gros morceau. Après quelques mouvements, vous pouvez simplement revenir à utiliser
mv ./subdir/* ./
la source
Voici mes deux cents, ajouter ceci dans
.bash_profile
Usage
la source