Comment l'entrée standard d'un programme peut-elle être passée en argument à un autre?

17

Disons qu'un programme existe, qui prend deux arguments; fichier d'entrée et fichier de sortie.

Que faire si je ne souhaite pas enregistrer ce fichier de sortie sur le disque, mais plutôt le transmettre directement à stdinun autre programme. Existe-t-il un moyen d'y parvenir?

Beaucoup de commandes que je rencontre sous Linux fournissent une option pour passer '-' comme argument de fichier de sortie, ce qui fait ce que j'ai spécifié ci-dessus. Est-ce parce que le passage stdind'un programme en argument n'est pas possible? Si tel est le cas, comment procédons-nous?

Un exemple de la façon dont je voudrais l'image en utilisant ceci est:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" stdin(echo)

Le shell que j'utilise est bash.

Dziugas
la source
1
cat <file | cmd /dev/fd/0fonctionne sur la plupart des unités.
mikeserv du
Ne travaille pas pour moi. Essayé avec: cat < README.txt | cp /dev/fd/0. Il a ditcp: missing destination file operand after ‘/dev/fd/0’ Try 'cp --help' for more information.
Dziugas
1
program input-file /dev/stdout | another-program? Notez également que echone lit rien de stdin.
yaegashi
1
@Dziugas - bien sûr que non - vous ne pouvez pas cpun fichier nulle part. echo 1 2 3| cp /dev/fd/0 /dev/ttyva imprimer 1 2 3. Et en passant, /dev/fd/[num]est plus susceptible de fonctionner que /dev/std(in|out|err)dans la plupart des cas. Voir Portabilité des liens descripteurs de fichiers sur ce à quoi vous pouvez vous attendre à travailler où.
mikeserv
1
Un bon programme UNIX écrirait sur la sortie standard en laissant à l'utilisateur le soin de décider s'il souhaite rediriger vers un fichier ou diriger vers une autre commande.
Jorge Bucaran

Réponses:

13

Si le programme prend en charge l'écriture dans n'importe quel descripteur de fichier même s'il ne peut pas le rechercher, vous pouvez l'utiliser /dev/stdoutcomme fichier de sortie. Il s'agit d'un lien symbolique vers /proc/self/fd/1mon système. Le descripteur de fichier 1 est stdout.

TiCPU
la source
Cela a résolu ma requête. N'y a-t-il donc aucun moyen de le faire lorsque le programme doit chercher?
Dziugas
3
Si vous essayez d'empêcher l'accès au disque, vous pouvez écrire le fichier dans / dev / shm /, cependant, si vous ne voulez pas de fichier sur le système de fichiers, à ma connaissance, il n'y a aucun moyen de chercher sur un tuyau. Chercher en avant signifie qu'il devrait tout mettre en mémoire tampon jusqu'à ce qu'il atteigne ce point en avant, et chercher en arrière implique d'avoir tout mis en mémoire tampon.
TiCPU
pdftotextcomme beaucoup (mais pas tous) d'autres utilitaires prennent également en charge -cela (qui fonctionnerait même sur des systèmes qui ne prennent pas en charge / dev / stdout, ou où / dev / stdout ne fonctionne pas comme prévu comme sur Linux où stdout n'est pas un tuyau). pdftotext file.pdf - | wc -c
Stéphane Chazelas
11

Depuis la pdftotextpage de manuel:

Si le fichier texte est ´- ', le texte est envoyé à stdout.

Donc, dans ce cas, tout ce dont vous avez besoin est:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" -

Ou si vous voulez diriger ceci vers STDIN d'un autre programme:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" - | another_prog

L'utilisation -comme substitut d'un nom de fichier est une convention que de nombreux utilitaires suivent (y compris pdftotext) lorsque nous voulons une entrée depuis STDIN ou une sortie vers STDOUT. Cependant, tous les utilitaires ne suivent pas cette convention. Dans ce cas, la façon idiomatique de le faire dans bash est d'utiliser une substitution de processus :

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( cat )

Ici, le >( )comportement se fait en grande partie comme un fichier transmis à my_utility, mais au lieu d'être un vrai fichier, le flux est canalisé dans le stdin du processus contenu, c'est-à-dire cat. Donc, ici, le texte devrait finalement sortir comme requis.

L'utilisation de catpresque toujours déclenche des sonneries d'alarme UUOC sur des forums comme celui-ci. Je soutiens que si l'utilitaire ne prend pas en charge -, c'est une utilisation utile de cat, bien que s'il existe des moyens de faire cette substitution de processus sans le cat, alors je suis à l'écoute ;-).

Cependant, si (comme l'indique la question) la destination finale du flux est STDIN d'un autre programme, alors le catpeut être éliminé:

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( another_prog )
Traumatisme numérique
la source
2
Et permettez-moi de revenir en arrière une fois de plus: si prog2écrit sur stdout, c'est mieux que , car le formulaire attend la fin (c'est-à-dire avant que le shell émette l'invite suivante ou passe à la commande suivante (par exemple, après ou )), tandis que le -les formulaires n'attendent que d' être complétés. En outre, après le formulaire, est le statut de sortie de , tandis que, dans l'autre, est le statut de sortie de . (Vous payez votre argent et vous faites votre choix.)prog1 input_file >( cat ) | prog2prog1 input_file >( prog2 )catprog2;&&catprog1cat$?prog2$?prog1
Scott
4

Si votre shell les prend en charge, la manière la plus simple de faire de telles manipulations serait d'utiliser la substitution de processus : <(…)et >(…). Cela fonctionne dans bash, zsh et ksh et éventuellement dans d'autres shells. Par exemple:

$ sort <(printf "b\nc\na\n")
a
b
c
$ ls
foo
$ cp <(find . -name foo) bar
$ ls
bar  foo

Cependant, cela n'aidera pas dans l'exemple que vous indiquez, car il pdftotextsera enregistré dans un fichier texte. Bien que votre meilleur choix (en dehors de l'utilisation évidente -) soit d'utiliser /dev/stdoutcomme suggéré par @TiCPU, vous pouvez également utiliser une autre fonctionnalité de shell. La construction !:Nfait référence au Nième argument de la commande précédente. Par conséquent, vous pourriez faire:

$ pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"  out.txt
$ cat !:2
terdon
la source
1
Bien que je convienne que cela cat <()peut être utile dans certaines situations, dans ce scénario, cependant, cela ne fonctionne pas du tout. Le problème (très mal décrit par OP, je dois l'avouer) est qu'il pdftotextprend deux arguments: le fichier d'entrée et le fichier de sortie . Si le deuxième argument est manquant, il ne produit rien, donc cat <(pdftotext "file.pdf")ne retournerait rien non plus. On peut tricher pdftotextcommande en donnant >(cat)comme deuxième argument comme Digital Trauma a répondu, mais cat <()est inutile ici. Évidemment, dans le pdftotextcas où il est préférable de l'utiliser -comme nom de fichier de sortie.
jimmij
1
@Scott Comment ma réponse est-elle une UUOC? Comment feriez-vous ce processus de substitution sans chat? >( )dirigera efficacement le flux vers le processus à l'intérieur - nous avons donc réellement besoin d'un catici pour sortir ce flux. Normalement, nous devrions pouvoir faire quelque chose comme pdftotext input.pdf -, mais apparemment pdftotextne prend pas en charge le -paramètre pour sortir directement vers stdout au lieu d'un fichier - essayez-le.
Digital Trauma
1
@DigitalTrauma ce n'est pas uuoc. Je crois que cat est le plus rapide que vous pouvez obtenir en cas de simple impression, mais en fait, vous pouvez utiliser une autre commande >(grep something)pour être plus utile. BTW, mon pdftotext 3.04 do support en -tant que fichier de sortie, donc je suis un peu surpris par toute discussion.
jimmij
1
@terdon Je déteste être tenace, mais cela ne semble pas fonctionner. Plus précisément, ce n'est pas différent de l'exécution pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf", qui place la sortie dans un fichier appelé C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.txt, mais aucun du texte n'est sorti vers STDOUT pour être redirigé vers un autre programme.
Digital Trauma
1
@DigitalTrauma qui n'est pas un stickler! C'est moi d'être un idiot. Merci de l'avoir signalé et veuillez ne jamais vous excuser en signalant des erreurs. Je préférerais de beaucoup que mon erreur me soit signalée et ainsi apprendre quelque chose plutôt que de le laisser là dans toute sa splendeur douteuse.
terdon
-2
cmd tty

ttyrenvoie le nom du terminal connecté stdout.

jas
la source
Je ne sais pas comment cela répond à la question, qui concerne la combinaison de commandes; peut-être vous développez avec un exemple de la façon dont vous pourriez y parvenir.
dhag
Je suppose que vous dites de vérifier avec ttyle nom du terminal, puis d'utiliser ce fichier comme sortie, par exemple pdftotext file.pdf /dev/pts/2. Dans ce cas, je suis d'accord.
jimmij
Cela peut être abrégé / automatisé en ; qui va généralement être équivalent à . Mais cette approche suppose que le but est d'afficher la sortie de (c'est-à-dire dans le terminal), et ce n'est pas ce que la question demande (voir les commentaires sur la réponse de terdon pour des éclaircissements sur le sens de la question). prog1  input_file $(tty)prog1  input_file /dev/ttyprog1
Scott