web-dev-qa-db-fra.com

Linux pourquoi ne puis-je pas diriger le résultat de recherche vers rm?

désolé si c'est une question noobie mais je ne trouve pas de bonne réponse.

Pour trouver puis supprimer quelque chose que je peux utiliser

find . -name ".txt" -exec rm "{}" \;

Mais pourquoi ne puis-je pas simplement diriger les résultats vers rm comme

find . -name ".txt" | rm 

comme je le ferais pour grep

find . -name ".txt" | grep a

J'ai lu quelque part que rm ne prend pas d'entrée de stdin et donc je ne peux pas le diriger mais qu'est-ce que cela signifie? Lorsque je tape rm a.txt, il lit à partir de l'entrée standard comme je peux le faire, non? Ou y a-t-il une différence entre stdin et la ligne de commande. Aidez-moi!

45
user1297061

Pour développer la réponse de @Alex Gitelman: oui, il y a une différence entre "l'entrée standard" et la ligne de commande.

Lorsque vous tapez rm a.txt b.txt c.txt, les fichiers que vous listez après rm sont appelés arguments et sont mis à la disposition de rm via une variable spéciale (appelée argv en interne). L'entrée standard, d'autre part, ressemble à un programme Unix comme un fichier nommé stdin. Un programme peut lire les données de ce "fichier" comme s'il le faisait s'il ouvrait un fichier normal sur le disque et le lire.

rm, comme beaucoup d'autres programmes, prend ses arguments depuis la ligne de commande mais ignore l'entrée standard. Vous pouvez y ajouter tout ce que vous voulez; il va juste jeter ces données. C'est là que xargs est utile. Il lit les lignes sur l'entrée standard et les transforme en arguments de ligne de commande, afin que vous puissiez efficacement diriger les données vers la ligne de commande d'un autre programme. C'est une astuce intéressante.

Par exemple:

find . -name ".txt" | xargs rm
find . -name ".txt" | grep "foo" | xargs rm  

Notez que cela ne fonctionnera pas correctement s'il existe des noms de fichiers contenant des sauts de ligne ou des espaces. Pour traiter les noms de fichiers contenant des sauts de ligne ou des espaces, vous devez utiliser à la place:

find . -name ".txt" -print0 | xargs -0 rm

Cela indiquera à find de terminer les résultats avec un caractère nul au lieu d'une nouvelle ligne. Cependant, grep ne fonctionnera pas comme avant. Utilisez plutôt ceci:

find . -name ".txt" | grep "foo" | tr "\n" "\0" | xargs -0 rm

Cette fois, tr est utilisé pour convertir toutes les nouvelles lignes en caractères nuls.

90
Tim Pierce

"pourquoi ne puis-je pas trouver le résultat vers rm?"

Lorsque vous dirigez quelque chose vers un programme, le canal remplace l'entrée clavier. Gardez cela à l'esprit et posez-vous la question suivante: Que ferait rm avec un clavier? Supprimer vos frappes? (un peu idiot en effet) Accepter le contrôle interactif? (rm n'est pas interactif sauf parfois quand il a besoin d'une confirmation, qui peut en effet être donnée par un pipe.)

En fait, lorsque rm est déjà en cours d'exécution, vous ne pouvez pas taper de commandes pour lui permettre de supprimer des fichiers .... vous ne pouvez donc pas le faire avec un canal non plus.

Si vous gardez à l'esprit qu'un tuyau remplace la combinaison clavier/écran, les choses apparaîtront immédiatement plus logiques.

Maintenant l'inverse. Vous pouvez diriger un flux de données dans grep. Cela signifie-t-il que vous pouvez laisser grep lire les séquences de touches de votre clavier en tant que données d'entrée?

OUI! C'est en fait ce qu'il fait nativement (sans tuyauterie).

(b.t.w. notez que vous ne pouvez pas diriger ni taper l'argument de recherche dans grep)

Alors maintenant, vous savez pourquoi vous ne pouvez pas diriger vers rm et vous attendre pour fonctionner comme un argument de ligne de commande.

tl; dr:

Anatomie d'un programme selon la philosophie UNIX:
entrée de fichier, sortie de fichier, entrée de clavier, sortie d'écran. -> Le tuyau ne remplace que le clavier et l'écran.

5
thom

Le tuyau envoie la sortie de la première commande à l'entrée standard de la seconde. rm n'accepte pas l'entrée standard, vous ne pouvez donc pas y accéder. Vous pouvez utiliser xargs pour obtenir le même effet. Vous pouvez trouver un exemple pour xargs spécifiquement pour votre cas dans page de manuel pour xargs .

4
Alex Gitelman

Une alternative sans utiliser de tuyaux:

xargs rm -f <<< $(find . -name ".txt")
2
Salvatore De Fidio