Passer le texte au programme attendant un fichier

30

Lié à une question que j'ai posée sur Stack Overflow: Passer plusieurs lignes de code à wsadmin.sh? .

J'ai, en tant que chaîne, quelques lignes d'entrée dont j'ai besoin pour alimenter une commande. Cependant, la commande n'accepte qu'un fichier plein d'entrée.

Existe-t-il un moyen de stocker les lignes dans un fichier temporaire ou un tube qui ne sera jamais réellement écrit sur le disque, puis de l'introduire directement dans le programme?

Comment dois-je procéder pour acquérir le tuyau, y introduire l'entrée, passer ce tuyau à la commande, puis se débarrasser du tuyau?

ArtOfWarfare
la source
2
Pouvez-vous ajouter un exemple de la commande que vous utilisez et comment elle est censée être invoquée?
Percée du
2
Est-ce à dire que le programme n'accepte pas stdin?
Léo Lam
Je suis d'accord avec les deux commentateurs ci-dessus. Il est impossible de suggérer quoi que ce soit qui puisse fonctionner sans connaître les spécifications du programme.
Larssend

Réponses:

27

Une autre solution consiste à utiliser la substitution de processus dans Bash. Si votre système a nommé des canaux, vous pouvez utiliser cette fonctionnalité.

Il est utilisé comme ceci:

program_expecting_a_file <(list)

listest une séquence de commandes shell (en fait des pipelines; les détails complets sont ici ). listsera exécuté et sa sortie sera connectée au tuyau. Le nom du canal est ensuite transmis à votre programme.

REMARQUE: les espaces ne sont pas autorisés entre <et (.

(L'autre substitution >(list)fonctionne également comme prévu.)

Dans votre cas spécifique, vous pouvez utiliser

program_expecting_a_file <(echo "$your_strings")

bien que vous puissiez trouver la solution de @ meuh plus élégante.

Mise à jour: de nombreux exemples d'utilisation sont disponibles dans le Guide de script avancé de Bash .

Edward
la source
Les deux autres n'ont pas fonctionné même dans les cas les plus triviaux. Le vôtre passe les tests que je lui ai lancés jusqu'à présent. J'ai voté pour le vôtre pour l'instant. Je reviendrai et marquerai cela comme accepté s'il fait tout ce dont j'ai besoin.
ArtOfWarfare
Le vôtre fonctionne parfaitement. Si vous le souhaitez, vous pouvez l'ajouter à la question connexe sur StackOverflow et je peux également l'accepter là-bas. stackoverflow.com/questions/31374202/…
ArtOfWarfare
Salut @ArtOfWarfare, heureux de vous aider. Il y a déjà un commentaire là-bas avec la même solution proposée, il ne serait donc pas juste que je poste une réponse là-bas.
Edward
Vous avez publié votre solution avant lui. Quoi qu'il en soit, je lui ai demandé de changer son commentaire en une réponse afin que je puisse l'accepter. Si aucun de vous ne répondez dans les ~ 24 heures à cette question, je posterai la réponse moi-même pour que je puisse l'accepter (je n'aime pas laisser mes questions comme sans réponse une fois que j'ai trouvé la réponse. juste de mauvaises manières pour les futurs lecteurs / répondeurs potentiels de la question.)
ArtOfWarfare
Salut @ArtOfWarfare, je suis absolument d'accord avec ce que vous proposez!
Edward
15

Vous pouvez utiliser un bash here-doc . Par exemple,

$ cat -n <<<'a
> b'
 1  a
 2  b

Si vous avez quelque chose dans une variable bash, vous pouvez également l'interpoler: par exemple <<<"path is $PATH".


Si votre commande insiste sur un nom de fichier, vous pouvez le lui donner /dev/stdin. Par exemple:

$ sed -f /dev/stdin <<<'s/a/b/'

produit la sortie: s/b/b/.

meuh
la source
Il n'est pas clair à partir de la question de savoir si la commande accepte la saisie stdin, et sinon, cela ne fonctionnera pas. J'espère que le PO clarifie.
David Z
1
:( - Cela semblait super prometteur, mais quand je l'ai essayé, j'ai reçu le message d'erreur"-f" option must be followed by a file name.
ArtOfWarfare
Un here-doc est pour stdin. Si votre commande a absolument besoin d' -fun nom de fichier, indiquez-le /dev/stdin. Voir mon montage.
meuh
Je pense qu'après les modifications, c'est une option absolument viable!
Edward
1
+1 pour la /dev/stdinsuggestion. Le programme que j'essaie d'appeler n'accepte qu'un nom de fichier, j'ai donc combiné /dev/stdinavec un hérédoc.
Huw Walters le
7

Selon le contenu du script, vous pourrez peut- être utiliser le nom de fichier spécial - (moins) qui signifie stdin

$ mycmd -
Line 1
Line 2
^D

Une autre méthode qui peut fonctionner pour vous consiste à ouvrir le fichier /dev/fd/0qui représente à nouveau stdin .

Une troisième option peut être de créer un FIFO (First In First Out). C'est comme un fichier, mais il a deux extrémités: vous écrivez à une extrémité et lisez de l'autre.

-- Process 1 --                  -- Process 2 --
$ mkfifo foo
$ cat foo
<waits>                          $ echo hello > foo
hello                            $
$ rm foo
Majenko
la source
3
Il peut être intéressant de noter que le programme doit être écrit pour interpréter de -cette façon - ce n'est pas une fonction du shell ou du système d'exploitation. Bien sûr, la plupart des utilitaires Linux standard suivent cette convention, pour autant que je sache.
David Z
1
Nan. Cela ne fonctionne pas pour le programme. Il y a un mode interactif, mais je veux passer les commandes à exécuter à ce programme à partir d'un autre programme, et je ne veux pas entrer dans le lapin expect.
ArtOfWarfare
@ArtOfWarfare Je viens d'ajouter une troisième option qui pourrait fonctionner.
Majenko
Bonne réponse! Les deuxième et troisième options sont essentiellement comme la <()solution, mais plus explicites - ce qui peut être très utile!
Edward
4

Il existe une autre option similaire à la mycmd -solution, mais même pour les programmes qui ne traitent pas -spécifiquement:

$ mycmd /dev/stdin
Line 1
Line 2
^D

/dev/stdin semble être lié au système d'exploitation et cela fonctionne pour moi sur Debian GNU / Linux, mais je ne sais pas où cela fonctionnera également.

Axel Beckert
la source
1
Cela semble fonctionner, mais qu'est-ce que c'est ^D?
ArtOfWarfare
^Dest une notation courante pour appuyer sur Ctrl-D. ^ D a ici la sémantique de "fin du flux d'entrée". Il est probablement plus souvent vu dans ^Cou ^Zqui signifie appuyer sur Ctrl-C respectivement pour appuyer sur Ctrl-Z.
Axel Beckert
1
Cela semble fonctionner, mais comment pourrais-je mettre par programme des trucs /dev/stdinpuis les fermer?
ArtOfWarfare
1
Il suffit de diriger quelque chose dans cette commande et cela devrait fonctionner, c'est-à-dire cat content | mycmd /dev/stdin. Imaginez simplement des commandes différentes catqu'ici.
Axel Beckert