Utiliser les données lues à partir d'un canal plutôt qu'à partir d'un fichier dans les options de commande


18

Par définition homme, cette commande obtient l'entrée d'un fichier.

$ command -r FILENAME

Supposons qu'il FILENAMEs'agit d'un fichier contenant une liste de noms de fichiers, tel qu'il a été généré à l'aide de ls > FILENAME.

Comment puis-je, au lieu de cela, alimenter la commande avec le résultat de lsdirectement? Dans ma tête, quelque chose comme ça devrait être possible:

$ ls | command -r

Mais ce n'est pas le cas, la sortie de lsn'est pas accrochée comme argument. Production:

Usage: command -r FILENAME
error: -r option requires an argument

Comment puis-je obtenir l'effet souhaité?


Plus de réponses à ce sujet dans une question connexe: Comment passer une chaîne à une commande qui attend un fichier?
ilkkachu

Réponses:


31

Cela dépend de la commande. Certaines commandes qui lisent à partir d'un fichier s'attendent à ce que le fichier soit un fichier normal, dont la taille est connue à l'avance, et qui peut être lu à partir de n'importe quelle position et rembobiné. Ceci est peu probable si le contenu du fichier est une liste de noms de fichiers: alors la commande se contentera probablement d'un tube qu'elle lira juste séquentiellement du début à la fin. Il existe plusieurs façons d'alimenter des données via un canal vers une commande qui attend un nom de fichier.

  • De nombreuses commandes traitent -comme un nom spécial, ce qui signifie lire à partir d' une entrée standard plutôt que d'ouvrir un fichier. C'est une convention, pas une obligation.

    ls | command -r -
  • De nombreuses variantes Unix fournissent des fichiers spéciaux /devqui désignent les descripteurs standard. S'il /dev/stdinexiste, l'ouvrir et le lire équivaut à lire à partir de l'entrée standard; de même /dev/fd/0s'il existe.

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
  • Si votre shell est ksh, bash ou zsh, vous pouvez faire en sorte que le shell s'occupe d'allouer un descripteur de fichier. Le principal avantage de cette méthode est qu'elle n'est pas liée à l'entrée standard, vous pouvez donc utiliser l'entrée standard pour autre chose et vous pouvez l'utiliser plusieurs fois.

    command -r <(ls)
  • Si la commande s'attend à ce que le nom ait une forme particulière (généralement une extension particulière), vous pouvez essayer de le tromper avec un lien symbolique.

    ln -s /dev/fd/0 list.foo
    ls | command -r list.foo

    Ou vous pouvez utiliser un tuyau nommé.

    mkfifo list.foo
    ls >list.foo &
    command -r list.foo

Notez que la génération d'une liste de fichiers avec lsest problématique car elle lstend à modifier les noms de fichiers lorsqu'ils contiennent des caractères non imprimables. printf '%s\n' *est plus fiable - il imprimera chaque octet littéralement dans les noms de fichiers. Les noms de fichiers contenant des retours à la ligne causeront toujours des problèmes, mais cela est inévitable si la commande attend une liste de noms de fichiers séparés par des retours à la ligne.


+1 pour énumérer toutes les possibilités. La substitution de processus OMI est la bonne réponse à cette situation.
glenn jackman

7

Ça devrait être:

ls | xargs -n 1 command -r

Modifier: pour les noms avec des espaces vides:

ls | xargs -d '\n' -n 1 command -r

Cela pourrait être problématique s'il commandpense qu'il a tous les noms de fichiers dont il aura besoin en même temps sur la ligne de commande. Certaines versions de xargs donneront commandquelques noms de fichiers (10, il me semble) à la fois. On dirait que GNU xargs donne tout à la fois.
Bruce Ediger

2

En fait, la seule solution fiable que je connaisse qui puisse gérer tous les noms de fichiers, y compris ceux qui contiennent une nouvelle ligne, est:

find . -maxdepth 1 -print0 | xargs -n 1 -0 command -r

Le seul caractère non autorisé dans le nom de fichier dans ce cas est le caractère nul, qui n'est de toute façon pas autorisé dans les noms de fichiers.


1

De nombreuses commandes acceptent -comme un "nom de fichier" qui signifie "utiliser l'entrée standard", mais cette convention est loin d'être universelle. Lisez la page de manuel.


1

Cela devrait fonctionner pour votre objectif: ls | command -r /dev/stdin

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.