Automating textual input from a bash script without using EOF

35,168

Solution 1

For nearly all programs, both echo $i | myprogram -options and myprogram -options <<<$i should work, by feeding the program $i through standard input.

<foo will use the contents of the file named foo as stdin.

<<foo will use the text between that and a line consisting solely of foo as standard input. This is a here document (heredoc), as Gilles said; EOF doesn't actually mean the end of the file, it's just a common heredoc delineator (we use "foo" instead in this example).

<<<foo will use the string "foo" as standard input. You can also specify a variable $foo, and the shell will use its contents as stdin, as I showed above. This is called a herestring, as it uses a short string in contrast to a whole block, as in a heredoc. Herestrings work in bash, but not in /bin/sh.

Solution 2

The syntax recommended by this website is called a here document. The input to the file program starts immediately below the line containing <<EOF, and it is not terminated by the end of the script, but by a line containing exactly the text EOF (take care not to have extra whitespace). By the way, you can use any end marker that doesn't contain any shell special character: EOF is not a keyword, it is merely traditional.

#!/bin/bash
for i in {1..100}
do
   myprogram -options <<EOF
$i
EOF
   for j in {1..42}; do
     myprogram2 <<EOF
$i
$j
EOF
   done
done

Solution 3

here documents as mentioned by both Kevin and Gilles above, or simple piping will work in many cases.

For more complicated situations, you may want to look into Expect or similar (e.g. the Expect::Simple CPAN module is a very easy to use perl implementation). personally, I prefer the perl module (Expect itself is tcl) but there are implementations for many common scripting languages. It's even possible to write a very primitive implementation of the idea in sh or bash using while and read.

The general idea of Expect and similar tools is to wait for a specified string or pattern in the output of a program, and then feed it whatever input you want.

A common example use is to automate login, by "expecting" (i.e. waiting for) the string "ogin:", send the login-name, then expect the string "word:" and send the password.

One final option, if you have the source of myprogram, is to just modify it to take the input you want to give it as a command line option. This might be a bit more work up-front, but will be a whole lot less aggravating than messing around with Expect or piping data into a program that wasn't designed to be used that way.

... and don't forget to submit your patch to myprogram back upstream :) Even if they don't like the way you've coded it, they might like the idea enough to add the feature themselves. Upstream devs tend to appreciate people who get off their butts and contribute rather than demand or complain.

Share:
35,168

Related videos on Youtube

eikonal
Author by

eikonal

Updated on September 18, 2022

Comments

  • eikonal
    eikonal over 1 year

    I'm running Ubuntu Linux. Suppose there is a program called myprogram. This program prompts the user for input; specifically, the user must type an integer when prompted and press Enter. I would like to automate this process using a bash script. In particular, I would like to execute myprogram, say, 100 times (using a counter i which goes from 1 to 100). On each execution of myprogram, I would like to enter the current value of i when prompted.

    (By the way, myprogram takes options/switches -options, all of which will be constant and thus specified within the bash script.)

    An incomplete skeleton of this bash script might be:

    #!/bin/bash
    for i in {1..100}
    do
       myprogram -options
    done
    

    Now I would like to modify the above code so that the current value of i is entered when prompted by the program. What is the best way to do this?

    The website of the software I am using suggests using <<EOF at the end of the myprogram -options line. I think that this tells bash to look at the "end of the file" for the input to use. But what if I don't want to place the input at the end of the file? What if I would like to put it immediately after the << or <?

    The reason is that things will get more complicated. For example, I may introduce an integer counter j that changes in some non-linear, non-sequential way. I would then want to feed the current value of j to myprogram on each iteration, but the value of j may change between the call to myprogram -options and the end of the file EOF.

    Do you have any suggestions?

  • Alessio
    Alessio almost 12 years
    in other words, EOF in this context means an end-of-file marker, not the actual end of the script file. the text "EOF" is any arbitrary text - whatever you use immediately after the << characters will indicate the end of the here-now document. I typically use EOF because it stands out and is very unlikely to be inside the herenow document if, e.g., i'm programatically-generating the shell script (which i do quite often).
  • Alessio
    Alessio almost 12 years
    that bolded EOF should be <underscore><underscore>EOF<underscore><underscore>
  • killermist
    killermist almost 12 years
    Using here-documents like this, I have often changed the ending marker to something much more meaningful (and less likely to be "randomly" matched), like END_OF_WHATEVER_FUNCTION. Sometimes, trying to "save" space/size is actually a waste of effort because it causes ambiguity as to what is actually happening.
  • Ratafia
    Ratafia about 10 years
    How can you sleep in between commands read from the script?
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 10 years
    @unexpected62 I don't understand what you're asking. You should probably ask a new question on this site. Be sure to give enough context.