Liste d'arguments erreur trop longue pour les commandes rm, cp, mv

629

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 mvet des cpcommandes ainsi? Si oui, comment résoudre ces commandes?

Vicky
la source
21
Vous trouverez peut-être ce lien utile
another.anon.coward
1
Cela peut également être pertinent http://mywiki.wooledge.org/BashFAQ/095
Lorenzo Belli
4
@jww: Et j'ai continué à penser pendant tant d'années que bash relève des "outils logiciels couramment utilisés par les programmeurs" - une catégorie dont les questions peuvent être posées ici!
Vicky
@Nik - L'ajout de "... dans un script" n'est pas convaincant. Lorsque le problème est réduit à un exemple minimal, complet et vérifiable , il s'agit simplement d'une question sur la façon d'exécuter une commande. Mes excuses si je manque quelque chose d'évident.
2018 à 7h19

Réponses:

876

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:

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

Avertissement: il s'agit d'une recherche récursive qui trouvera (et supprimera) les fichiers dans les sous-répertoires également. N'utilisez -fla 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:

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

Une autre option consiste à utiliser l' -deleteindicateur find :

find . -name "*.pdf" -delete
DPlusV
la source
7
Non, xargsdivise spécifiquement la liste et émet plusieurs commandes si nécessaire.
tripleee
7
@Dennis: -maxdepth 1doit être le premier argument après le chemin.
Barton Chittenden
54
Find a un -deleteindicateur pour supprimer les fichiers qu'il trouve, et même s'il ne le faisait pas, il serait toujours préférable d'utiliser -execpour exécuter rm, plutôt que d'appeler xargs (qui est maintenant 3 processus et un tube au lieu d'un seul processus avec -deleteou 2 processus avec -exec).
scragar
3
@ ÉdouardLopez ... Mais ceci lit une entrée délimitée NULL. Et le tout dangerous (broken, exploitable, etc.), c'est assez ridicule. Vous devez sans aucun doute être prudent lors de l'utilisation xargs, mais ce n'est pas tout à fait eval/evil.
Réinstallez Monica Please le
4
@scragar Avec l' -execappel rm, 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 utilisant xargsserait 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 -deletedevrait être le seul processus à invoquer.
neuralmer
397

tl; dr

C'est une limitation du noyau sur la taille de l'argument de ligne de commande. Utilisez forplutôt une boucle.

Origine du problème

Il s'agit d'un problème système, lié execveet ARG_MAXconstant. 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_MAXlimite. 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 exécutant:

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

Solution: utiliser la forboucle

Utilisez une forboucle 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:

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

Et exécutez-le:

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

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 findmais 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" :

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

Utiliser -maxdepth 1 ... -deleteau lieu de -exec rm {} +permet findd'exécuter simplement les appels système requis sans utiliser de processus externe, donc plus rapide (grâce au commentaire @chepner ).

Références

Édouard Lopez
la source
31
Excellente réponse, voici comment toutes les questions SO doivent être répondues. Merci!
2015
1
+1 pour avoir mentionné la forboucle. Je l'ai utilisé findauparavant, mais je cherche toujours comment le faire en oubliant les options, etc. tout le temps. forsemble plus facile à rappeler IMHO
Robert Dundon
3
Utilisé comme for f in *; do rm "$f"; donetravail comme un charme
abdul qayyum
3
La find -execsolution semble être BEAUCOUP plus rapide que la forboucle.
Threeve
2
Cinq ans plus tard à 4.15.0 ( 4.15.0-1019-gcppour ê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.
Matt M.
181

finda une -deleteaction:

find . -maxdepth 1 -name '*.pdf' -delete
ThiefMaster
la source
4
Cela retournerait toujours "Liste d'arguments trop longue". Au moins pour moi, il fait. L'utilisation xargs, selon la réponse de Dennis, fonctionne comme prévu.
Sergio
7
Cela ressemble à un bug dans find.
ThiefMaster
3
@Sergio avait le même problème, il était dû aux guillemets manquants autour du modèle de nom.
Luxian
argh, pourquoi un outil pour trouver des trucs a-t-il même un interrupteur pour la suppression? est-ce vraiment juste moi qui trouve inutile de dire le moins et aussi dangereux.
mathreadler
2
@mathreadler Il traite du fait qu'un cas d'utilisation courant -execest 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. -deletepermet findd'exécuter simplement les appels système requis sans utiliser de wrapper externe.
chepner
21

Une autre réponse consiste à forcer xargsle traitement des commandes par lots. Par exemple pour deleteles fichiers 100à la fois, cddans le répertoire et exécutez ceci:

echo *.pdf | xargs -n 100 rm

portforwardpodcast
la source
4
Pour supprimer une commande sous linux, ce qui peut être un désastre si vous êtes ingénieur et que vous avez tapé une erreur, je pense que c'est la plus sûre et je sais ce qui se passe. Pas compliqué, si vous manquez de taper un point, votre entreprise s'écroulera en une minute.
ArtificiallyIntelligence
1
Comment pouvons-nous en faire l'extension par défaut pour certaines commandes? Il y a beaucoup de commandes linux "standard" où l'on sait si elles en ont besoin toutes en même temps (comme "rm")
user1212212
1
Notez que cela ne fonctionne que là où se echotrouve un shell intégré. Si vous finissez par utiliser la commande echo, vous rencontrerez toujours la limite des arguments du programme.
Toby Speight
14

Ou vous pouvez essayer:

find . -name '*.pdf' -exec rm -f {} \;
Jon Lin
la source
Cela supprime également les fichiers des sous-répertoires. Comment éviter ça?
Vicky
@NikunjChauhan Ajouter l'option -maxdepth:find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Jon Lin
Je ne suis pas en mesure d'insérer l'option maxdepth
Vicky
Cette option peut être une option uniquement Linux, selon la réponse de @ Dennis, ci-dessus (la réponse sélectionnée).
jvriesem
12

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:

/bin/rm: Argument list too long.

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:

find . -type f -exec rm -v {} \;

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:

find . -type f -delete

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:

find . -type f -print -delete

… Ou même montrer combien de fichiers seront supprimés, puis le temps nécessaire pour les supprimer:

root@devel# ls -1 | wc -l && time find . -type f -delete
100000
real    0m3.660s
user    0m0.036s
sys     0m0.552s
Bibin Joseph
la source
Merci. J'ai fait sudo find . -type f -deletepour supprimer environ 485 000 fichiers et cela a fonctionné pour moi. A pris environ 20 secondes.
Nigel Alderton
11

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 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")

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

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é.

BigMike
la source
5
Je pense que cela ferait de très belles choses avec un fichier nommé par exemple-rf .. .pdf
ThiefMaster
oui ce serait le cas, mais généralement lorsqu'il est utilisé en shell, l'émetteur de la commande "devrait" donner un aperçu de ce qu'il fait :). En fait, je préfère rediriger vers un fichier, puis inspecter chaque ligne.
BigMike
2
Cela ne cite pas "$ f". C'est de cela que ThiefMaster parlait. -rfa 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.
Peter Cordes
7

Vous pouvez utiliser un tableau bash:

files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
    rm -f "${files[@]:I:1000}"
done

De cette façon, il sera effacé par lots de 1000 fichiers par étape.

danjperron
la source
2
Pour un grand nombre de fichiers, cela semble beaucoup plus rapide
James Tocknell
5

vous pouvez utiliser cette recommandation

find -name "*.pdf"  -delete
Sarath Ak
la source
4

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:

rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf

Vous pouvez également les supprimer via la commande find :

find . -name "*.pdf" -exec rm {} \;
Fabio Farath
la source
3
Non, rmn'a pas une telle limite sur le nombre de fichiers qu'il traitera (à part cela, argcil ne peut pas être plus grand que INT_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).
Toby Speight
3

S'il s'agit de noms de fichiers avec des espaces ou des caractères spéciaux, utilisez:

find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;

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.

Alejandro Salamanca Mazuelo
la source
Bien que cet extrait de code puisse résoudre la question, y compris une explication de comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir, pas seulement à la personne qui vous pose la question maintenant! Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limitations et hypothèses applicables.
Toby Speight
Tout l'intérêt -execest 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.)
tripleee
2

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

user3405020
la source
Je ne sais pas pourquoi quelqu'un a voté contre ceci, sans même commenter cela (c'est la politique, les gens!). J'avais besoin de supprimer tous les fichiers d'un dossier (la question n'est pas particulière au sujet des PDF, faites attention), et pour cela, cette astuce fonctionne bien, tout ce que vous avez à faire à la fin est de recréer le dossier qui a été supprimé lorsque J'ai utilisé `rm -R / path / to / folder".
Thomas Tempelmann
1
Cela fonctionne parce que dans le cas d'OP, il utilisait *, qui s'est étendu à une énorme liste de fichiers .pdf, donner un répertoire fera que cela sera traité en interne, donc, sans avoir à traiter le problème d'OP. Je pense que cela a été rejeté pour cette raison. Il pourrait ne pas être utilisable pour OP s'il a imbriqué un répertoire ou d'autres fichiers (pas pdf) dans son répertoire
Alvein
2

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

find <path> -type f -mtime +90 -exec rm -rf {} \;

Ex: pour les derniers fichiers 30 jours que vous souhaitez supprimer, utilisez la commande ci-dessous (-)

find <path> -type f -mtime -30 -exec rm -rf {} \;

Si vous voulez giz les fichiers depuis plus de 2 jours

find <path> -type f -mtime +2 -exec gzip {} \;

Si vous ne souhaitez voir les fichiers / dossiers que depuis un mois. Ex:

find <path> -type f -mtime -30 -exec ls -lrt {} \;

Au-dessus de 30 jours de plus seulement, répertoriez les fichiers / dossiers Ex:

find <path> -type f -mtime +30 -exec ls -lrt {} \;

find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} \;
raja
la source
2

Je suis surpris qu'il n'y ait pas de ulimitréponses ici. Chaque fois que j'ai ce problème, je me retrouve ici ou ici . Je comprends que cette solution a ses limites mais ulimit -s 65536semble souvent faire l'affaire pour moi.

dps
la source
1

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

find . -name "*.png" -mtime +50 -exec rm {} \;

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

Brugolo
la source
1

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.

ls | grep .pdf > list.txt
wc -l list.txt

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.

split -l 600 list.txt

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:

rm $(<xaa)
rm $(<xab)
rm $(<xac)

Désolé pour mon mauvais anglais.

thai_phan
la source
5
Si vous avez un fichier nommé, pdf_format_sucks.docxcelui-ci sera également supprimé ... ;-) Vous devez utiliser une expression régulière correcte et précise lors de la recherche des fichiers pdf.
FooF
1
Mieux, mais still_pdf_format_sucks.docxsera supprimé. Le point .dans ".pdf"l'expression régulière correspond à n'importe quel caractère. Je suggérerais "[.]pdf$"au lieu de .pdf.
FooF
1

J'ai rencontré ce problème plusieurs fois. De nombreuses solutions exécuteront la rmcommande pour chaque fichier individuel qui doit être supprimé. C'est très inefficace:

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

J'ai fini par écrire un script python pour supprimer les fichiers en fonction des 4 premiers caractères du nom de fichier:

import os
filedir = '/tmp/' #The directory you wish to run rm on 
filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir
newlist = [] #Makes a blank list named newlist
for i in filelist: 
    if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist
        newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist
for i in newlist:
    if 'tmp' in i:  #If statment to look for tmp in the filename/dirname
        print ('Running command rm -rf '+str(filedir)+str(i)+'* : File Count: '+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count
        os.system('rm -rf '+str(filedir)+str(i)+'*') #Actual shell command
print ('DONE')

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.

Pedro Montero
la source
1

Et un autre:

cd  /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm

printfest un shell intégré, et pour autant que je sache, il en a toujours été ainsi. Maintenant que ce printfn'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 la rmcommande remove ( ), à travers xargs, ce qui garantit qu'il tient suffisamment de noms de fichiers dans la ligne de commande afin de ne pas échouer la rmcommande, qui est un shell commander.

Le \0en printfsert un séparateur nul pour les noms de fichier dont sont ensuite traitées par xargscommande, en l' utilisant ( -0) comme séparateur, donc rmne manque pas quand il y a des espaces blancs ou d' autres caractères spéciaux dans les noms de fichiers.

lind
la source
1
Bien que cet extrait de code puisse résoudre la question, y compris une explication de comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir, pas seulement à la personne qui vous pose la question maintenant! Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limitations et hypothèses applicables.
Toby Speight
En particulier, s'il printfne s'agit pas d'un shell intégré, il sera soumis à la même limitation.
Toby Speight
0

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:

mkdir testit
cd testit
mkdir big_folder tmp_folder
touch big_folder/file1.pdf
touch big_folder/file2.pdf
mv big_folder/file1,pdf tmp_folder/
rm -r big_folder
mv tmp_folder big_folder

le rm -r big_foldersupprimera tous les fichiers dans big_foldern'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

Keithhn
la source
0

Pour tout supprimer *.pdfdans un répertoire/path/to/dir_with_pdf_files/

mkdir empty_dir        # Create temp empty dir

rsync -avh --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/

Supprimer des fichiers spécifiques à l' rsyncaide 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. "

rsync -avhn --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/

. . .

Cliquez sur trucs et astuces rsync pour plus de hacks rsync

Raman Kathpalia
la source
0

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)

# delete files
import os as os
import glob
import multiprocessing as mp

directory = r'your/directory'
os.chdir(directory)


files_names = [i for i in glob.glob('*.{}'.format('pdf'))]

# report errors from pool

def callback_error(result):
    print('error', result)

# delete file using system command
def delete_files(file_name):
     os.system('rm -rf ' + file_name)

pool = mp.Pool(12)  
# or use pool = mp.Pool(mp.cpu_count())


if __name__ == '__main__':
    for file_name in files_names:
        print(file_name)
        pool.apply_async(delete_files,[file_name], error_callback=callback_error)
mmann1123
la source
0

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!

asatsi
la source
C'est assez vague et vous oblige à avoir locateréinstallé quand vous aviez encore de la place sur votre disque.
tripleee
-2

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?

Kaplan Ilya
la source
3
Ce n'est pas du tout sûr et ne fonctionne pas avec les noms de fichiers contenant des sauts de ligne, pour souligner un cas d'angle évident. L'analysels est un antipattern commun qui devrait certainement être évité, et ajoute un certain nombre de bogues supplémentaires ici. Le grep | grepn'est tout simplement pas très élégant.
tripleee
Quoi qu'il en soit, ce n'est pas comme si c'était un problème nouveau et exotique qui nécessite une solution complexe. Les réponses avec findsont 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.
tripleee
-2

Utiliser GNU parallel ( sudo apt install parallel) est super facile

Il exécute les commandes multithread où '{}' est l'argument passé

Par exemple

ls /tmp/myfiles* | parallel 'rm {}'

Jonathan
la source
Je ne sais pas, mais je suppose que c'est parce que passer la sortie de lsdirectement à 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écution lscomme expérimenté dans la rmcommande d' origine .
Toby Speight
Pour le contexte à ce sujet, voir ParsingLs . Et parallelrend 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 -Pparalè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.
Charles Duffy
-2

Pour supprimer les 100 premiers fichiers:

rm -rf 'ls | tête -100 '

Nikunj Ranpura
la source
2
Dangereux (ou ce serait le cas si vous utilisiez des guillemets comme prévu) - si un nom de fichier contient des métacaractères shell, y compris des espaces, les résultats ne seront pas ceux que vous vouliez.
Toby Speight
-5

L'option ci-dessous semble simple à ce problème. J'ai obtenu cette information d'un autre fil, mais cela m'a aidé.

for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
    cp "$file" /opt/sw/op-storage/
done

Exécutez simplement la commande ci-dessus et elle fera la tâche.

Amittal
la source