Shiny Prompt |
How do prompts work?
We use prompts without thinking what they really mean. A prompt is a way for the computer (or shell) to is printed to the screen when the current command is finished, usually a $, %, >, or #. It is the heart of an interactive program which is asking for user input.With expect-lite, the prompt indicates that the computer is ready to receive the next command. Much work has gone into expect-lite to detect the standard shell prompts. But what if you are automating a install script where the prompt is something like '(yes/no)? '*. How does one automate that?
Two solutions
- Use a user-defined prompt with the */myprompt / syntax. It is defined using regex and any characters in your prompt which are special to regex must be escaped with a backslash. Of the above yes/no prompt, the code would look like:
*/\(yes/no\)\? /
>yes - Use a non-regex expect line, followed by the answer with a no-wait-for-prompt send
<<yes/no
>>yes
While using the user-defined prompt is a more elegant solution, however it can be difficult to define the prompt without having a good knowledge of regex. The nice aspect of the second solution is although a bit wordy, no knowledge of regex is required. One only remember that the double >> means "do not wait for prompt".
Interaction of expect lines << and prompts
expect-lite is always searching forward when looking for an expect line. Take the following example:$ ssh 6palolo
The authenticity of host '6palolo (2001:470:ebbd:0:221:2aff:fec3:6ab0)' can't be established.
RSA key fingerprint is SHA256:tFStOlPO2dKJyqGE6D+7C8b1xu/4.
Are you sure you want to continue connecting (yes/no)?
yes
And the following script:
*/\(yes/no\)\? /
>ssh 6pallolo
<<continue connecting (yes/no)
>yes
This script will always fail. The expect-lite search buffer is NOT line oriented. It is just searching a blob of text including new-lines. The reason the script will fail is that the third line, an expect line, will consume the text '(yes/no) ', and when the script continues and looks for the user-defined prompt it will no longer be in the search buffer, and the script will fail.
A better way to write the script is to not expect what the user-defined prompt will look for:
*/\(yes/no\)\? /
>ssh 6pallolo
<continue connecting
>yes
Lastly, method 2 can be used which does not require a user-defined prompt. expect-lite will wait for the text continue connecting before it sends yes.
>ssh 6pallolo
<<continue connecting
>>yes
Creating consistent reproducible scripts
In the end, you want to write a readable script which runs in a reproducible manner. Many times using method 2 (without user-defined prompts) is the easier path. But expect-lite allows you to create your own prompt detection, making your life easier, because expect-lite is about automation for for the rest of us.* ssh will ask about continuing a connection to a new host by prompting with (yes/no)?
** Reminder that << means expect without regex interpretation, and >> means send without waiting for prompt