ls | grep | rm - Comment formater cette commande?

11

J'essaie de supprimer un tas de fichiers dans un certain répertoire (sur Mac OS X en utilisant Terminal)

ls | grep \([1-9]\) | xargs rm

devrait faire l'affaire, mais ce n'est pas le cas. J'essaie de supprimer n'importe quel fichier avec un seul chiffre entre parenthèses dans le nom de fichier (doublons téléchargés à partir du Web), mais cela finit par faire quelque chose comme ceci:

> rm: 520syllabus2010: No such file or
> directory rm: (3).pdf: No such file or
> directory

car il n'interprète pas correctement l'espace. Il devrait supprimer "520syllabus2010 (3) .pdf"

Quelle est la bonne façon de procéder?

Merci, Jeff

Jeff
la source
1
Votre exemple de nom de fichier ne contient pas de littéral #.
Benjamin Bannier
1
@honk: Il ne cherche pas un littéral #.
Ignacio Vazquez-Abrams
1
En raison de l'expansion par le shell, cela ne fonctionnera pas comme prévu si le cwd a un fichier nommé eg (3). Il est préférable de citer des arguments pour que le shell ne les affecte pas.
Ignacio Vazquez-Abrams
1
Vous êtes touché par Le problème du séparateur en.wikipedia.org/wiki/Xargs#The_separator_problem
Ole Tange

Réponses:

19

Version courte:

rm *\([1-9]\)*

Ne pas diriger lsvers xargs. Au lieu de cela, dirigez-vous find ... -print0vers xargs -0, afin d'éviter de tels problèmes.

find . -maxdepth 1 -name '*([1-9])*' -print0 | xargs -0 rm

... qui peut s'écrire:

find . -maxdepth 1 -name '*([1-9])*' -exec rm {} \;

et:

find . -maxdepth 1 -name '*([1-9])*' -delete

qui peut encore être raccourci rmavec un caractère générique.


Normalement, lset findséparez les noms de fichiers par des retours à la ligne, mais xargsdivisez son entrée par un retour à la ligne ou un espace, ce qui entraîne le comportement que vous voyez.

Il est possible de dire xargsde diviser uniquement par nouvelle ligne, mais les fichiers peuvent également avoir des nouvelles lignes dans leurs noms. En fait, sous Linux et BSD, le seul caractère interdit est le "nul" ou zéro octet - c'est donc ce que vous devez utiliser dans de tels cas.

Dans l'exemple 2 ci-dessus, -print0indique findde séparer les noms de fichiers avec un octet nul; pareil pour xargs -0. (Quelques autres outils ont également des options similaires, comme sort -zou grep -zZ.)

La «version courte» utilise un simple caractère générique de shell («modèle» dans le bashmanuel - voir la section «Expansion du nom de chemin»).

user1686
la source
1
Et juste pour être sûr, il est préférable d'utiliser *" "\\([1-9]\\).*afin que seuls les fichiers avec un espace avant le numéro de parent avant la période (a, pour être juste) soient supprimés.
Ignacio Vazquez-Abrams
Pas très familier avec cette syntaxe, mais sur la base des votes positifs, j'ai fait un essai et que savez-vous ... cela a fonctionné! Merci!
Jeff
1
+1. -print0 est essentiel pour une tuyauterie correcte vers xargs.
Chris W. Rea