I use InstallAnywhere in console mode in Linux for installation and want to run some interactive shell script after finishing the installation. By "interactive" I mean that the script should ask some questions and receive user input.
I tried to run it with "Execute target file" action, but the script prints nothing to the console (it surely executed because prints debug information to output file). I also tried to bring the script to foreground using "fg %1" (it was the last command in InstallAnywhere), but it did not work too.
Is there any way to execute interactive script by InstallAnywhere in console mode?
Rather than using a shell script for user interaction, leverage IA to collect the answers you need, stuff them into IA variables, then use those variables in one or more "Execute Script/Batch file" Actions to do the post-install work.
Say you want to collect a first name, last name and phone then write those to a file in your installation directory (contrived, I know, but hopefully demonstrative).
Add a Jump Label and name it something like "Get User Info"
Add the Console Action "Get User Input" to read the first name. Assign the result to $FIRST_NAME$.
Add the Console Action "Get User Input" to read the last name. Assign the result to $LAST_NAME$.
Add the Console Action "Get User Input" to read the phone number. Assign the result to $PHONE_NUMBER$.
Add the "Jump To Target" Action with a NEXT Jump Action of "Get User Info" (#1, above). Add rules to validate these three variables such that a TRUE result will execute the jump to "Get User Info". In other words, a BAD first name or BAD last name or BAD phone number should evaluate to TRUE. This will send the user back to the "Get User Info" Target Label. Three valid values should evaluate to false, thereby NOT executing the jump. I know. It's weird.
Finally, add as many "Execute Script/Batch file" Actions as needed to for each target installation platform. For each of these actions, add a rule that limits execution of that Action to a specific platform. For the Unix/Linux actions, be sure to check the checkbox "Do not substitute unknown variables" or IA will substitute YOUR script variables with blanks. (word of caution: use the full variable name form ${MY_VARIABLE_NAME} to help IA distinguish your variables from its own variables).
A Unix/Linux version might look like this:
#!/bin/sh
echo <<EOF
Name: $FIRST_NAME$ $LAST_NAME$
Phone: $PHONE_NUMBER$
EOF > $USER_INSTALL_FOLDER$$/$userName.txt
The Windows version is similar:
echo "Name: $FIRST_NAME$ $LAST_NAME$" > $USER_INSTALL_FOLDER$$/$userName.txt
echo "Phone: $PHONE_NUMBER$" >> $USER_INSTALL_FOLDER$$/$userName.txt
Note the use of $/$ which IA converts to the appropriate path separator for the current platform.
After the "Execute Script/Batch file" Actions you can add steps to evaluate the success of the Script/Batch file. Add rules on "Jump To Target" Actions to evaluate the value of $EXECUTE_EXITCODE$. $EXECUTE_EXITCODE$ is the default variable where the process' exit code is stored by "Execute Script/Batch file" Actions.
Real-life installation scripts could be more complex than this. You could collect any number of variables and use them in any number of post-installation script(s). These scripts then focus on doing the work, not on talking to the user. That should be IA's job.
Two parting thoughts:
First, this same technique could be used with a GUI installer, too. In fact, mixing GUI and console input actions in the same project extends your installer to both graphical and console target platforms. The Post-Install scripts remain the same regardless of how you collect the input.
Finally, you should ask your questions (if possible) during Pre-Install. That way the user can decide to bail on the installation if they can't or won't answer the questions. Asking the questions during post-installation could leave the installation hanging, or force the user to roll back, if they are unwilling or unable to provide the information you need.
Related
I'm a Debian Stretch user coming from Windows. In Windows with the launchy app (also available for Linux), I had a method of entering text into launchy that was then appended to the end of a .txt or .md file.
To do this in Windows, I created a file called note.bat that contained the following:
echo %*>>"C:\collectednotes.md"
I'd make launchy aware of note.bat by adding its containing folder to “Launchy” → “Settings” → “Catalog” and adding filetype *.bat.
From there, I'd launch launchy, type note, hit Tab, enter some text, hit Enter, and then the text would be added to the end of collectednotes.md.
A mostly working process is detailed in my answer below. I'll give the green checkmark answer to anyone that can adjust this process (via note.sh and/or launchy plugin setup detailed below) to appropriately handle all special characters.
This may contain the solution to this question:
Which characters need to be escaped in Bash? How do we know it?
Solved (almost). I'm keeping this question unanswered and will give to whoever completes the remaining ~5%. Steps to get the 95% solution with xfce4-terminal version 0.8.3-1:
Install launchy and launchy-plugins (both are version 2.5-4 for me):
apt-get install launchy
apt-get install launchy-plugins
Open terminal to default location of ~/ and create collectednotes.md:
echo "# Launchy Notes Collected Here" > collectednotes.md
Create note.sh shell script:
echo '#!/bin/sh' > note.sh
Create shell script line 2:
echo ALL_ARGUMENTS='"$#"' >> note.sh
Create shell script line 3:
echo 'echo "$ALL_ARGUMENTS" >> ~/collectednotes.md' >> note.sh
If you open note.sh, it will look like:
#!/bin/sh
ALL_ARGUMENTS="$#"
echo "$ALL_ARGUMENTS" >> ~/collectednotes.md
Make note.sh executable:
chmod +x note.sh
Launch launchy and click the gear icon in upper right for settings. If consistency with launchy for Windows is desired, set launchy Hotkey to Alt+Space. If you receive a keyboard shortcut conflict message as I do on Debian with Xfce, first go to Settings, Window Manager, Keyboard tab, and clear Alt+Space as the shortcut for Window operations menu.
Next in launchy settings, go to Plugins tab and enable the plugin Runner. Click the + button and create a new Runner custom command as follows:
- Name: note
- Program: /home/YOURUSERNAMEHERE/note.sh (launchy does not like Program path of ~/note.sh, so a specific path with username is required)
- Arguments: '$$'
Click the Catalog tab and hit Rescan Catalog just in case. Hit OK to close launchy settings.
Now let's test it.
- launch launchy with Alt+Space or your hotkey
- type note (You may have to wait 10 second or so on first run. You'll know things are as expected when you see the text "note" with a orange/yellow icon containing silhouette of a person.)
- hit Tab
- enter some text (no need for single or double quotes or escapes), e.g.: Remember to donate at least $3 to Josh at Launchy https://www.launchy.net/donate.php
- hit Enter
Now open collectednotes.md to confirm the text was captured.
The remaining issues seem to be dealing with single quotes and double quotes. For example, consider the following note:
I don't know what I'd do without Launchy.
Which results in the following in collectednotes.md:
I dont know what Id do without Launchy.
Or:
Would David Allen like universal text capture from anywhere in Linux? My bet is "yes!"
Results in the following in collectednotes.md:
Would David Allen like universal text capture from anywhere in Linux? My bet is \yes!\
Single quoting and/or double quoting the input to launchy doesn't solve it. Note the launchy Runner custom plugin construction component of '$$' is a piece of this puzzle.
I'll give the answer to anyone that can adjust this process (via note.sh and/or launchy plugin setup) to appropriately handle all special characters. Maybe this would add proper escapes to user input with something like gsub.
The rationale for being exacting regarding proper character handling is that this process is useful for copying and logging random chunks of text from web pages, but if common characters like single quotes are not handled as expected, confidence in the system is much reduced.
I'm working on a shell script, which has lot of network calls and installations. When it is executed I need to enter yes/no for each prompt. Which is fine.
But now i have a requirement to run it as cron. In which case i won't be able to give inputs for each of the prompt that comes up.
Is there any way I can automate this or have some mechanism of knowing in script that a prompt has come up?
Use the yes command to answer interactive prompts,
yes Y | ./script.sh
The above syntax constantly puts the string Y to all your prompts. You can pass the string as you need after yes.
You can also use expect tool meant for this, but you need to know the exact prompt message for capturing and responding to it accordingly. If your prompt is simple and just need a simple input to pass yes would be the right tool.
Also you can use bash built-in printf, but you need to add the responses manually depending upon the number of prompts you have to respond to, e.g.
printf 'Y\nY\nY\n' | ./script.sh
to send response as Y for three prompts. As again, to avoid doing this manually, prefer using the yes command.
I have a Bourne-Again shell script text executable named engine.bin that I want to install.
If I install the executable manually ./engine.bin I get a screen with the EULA I have to accept (by pushing space), then accept it by writing yes and then enter the installation path by typing /usr/local/engine.
Now I want to do the installation automatically through provisioning scripts without manual interaction. Is there a way to do this? I do not know if the installer accepts any parameters, unfortunately the thing is undocumented.
Based on the suggestion of bill-agee and jgr208 I wrote the following which is working for me:
#!/usr/bin/expect -f
set timeout -1
spawn /tmp/engine.bin
expect {
-gl "*Press SPACE or PAGE DOWN key to continue, U or PAGE UP key to scroll back*" { send -- " "; exp_continue }
-gl "*yes/no*"
}
send -- "yes\r"
expect -gl "*press ENTER to accept the default*"
send -- "/tmp/tce\r"
expect eof
If the executable allows you to spam input at it without waiting for each separate prompt to appear, you might be able to accomplish this with bash.
For example, this script will run program_that_takes_several_lines_of_input.py and send it four lines of input - three with text and one blank line:
#!/bin/bash -eux
./program_that_takes_several_lines_of_input.py <<EOD
first line
one enter keypress later
yet another line of input after the empty line above
EOD
If you need to stop and wait for each prompt to appear, the cram Python package may be a good fit for this scenario - I find it useful for tasks like this where you only need to send a few lines of input, but each line of input is different.
See:
https://bitheap.org/cram/
https://pypi.python.org/pypi/cram
Expect would also work, but I find that I reach working solutions a bit faster when using cram than with Expect.
pexpect is a great choice as well! See:
https://pexpect.readthedocs.org/en/stable/
I'm looking for a method to check from within my shell script that script specific completion have been initialized by user using complete -F ...
I want this check to print out an advice on how to initialize the completion like:
Warning: Auto completion is not initialized. Please run : source ....; complete -F ...
The problem is that the script,being run in a sub-shell has no information about "complete" environment of the parent shell where user is working.
So complete -p| grep my-script-name never return any result.
User is expected to run "source" and "complete" commands or add them into his .bashrc manually, because we're working on a server where we have no access to the bash completion system directory.
Alternatively if you know a method of initializing(and not only checking) the auto-complete from within the script, I would happily accept it.
The only way your script can have access to such information for the parent shell is if it is included instead of executed as a sub-shell. Rather than instructing your users they can include some configuration, you can design your script so it works whether it is run or included.
Then you can simply inform your users that if they want completion enabled they need to include your script rather than run it as an executable script (with instuctions to use source or . as you wish).
However, in this case, I would be inclined to either add this information in documentation or add it into a banner which is always displayed (but can be disabled with an option switch like -q), rather than support two modes of running the script (since the gain is so small).
Either you want every user to use bash completion (which I don't think is good, for example I prefer to have it turned off), or let users decide themselves, but having them this message printed out on each TABTAB is a threat, don't you think?
I'd put into /etc/bash.bashrc what you think every user should run.
We have a shell script that expects multiple user inputs to be entered when prompted. e.g
At first it may ask for the operation to be performed. When that answer is given, it may ask for username then password etc. We want to automate this task by providing the inputs using file redirection i.e.
script < input.
The input file will have all the answers for different questions that the script may ask. However it is not working and the shell script is reading only the first line of the input file. What do I need to change or use to make this work?
What you can use is the program expect. You create a script for it that tells it when to give what input to some command it executes. This way you can automate exactly the kind of thing you're struggling with.
More info on Google and here:
http://www.linuxjournal.com/article/3065
man page: http://linux.die.net/man/1/expect
You say 'it only reads the first line of input.'
So you have to kill the script?
Is there any output? (error messages especially)?
Are you redirecting STDERR to /dev/null or else where? If so, remove that.
Here is the hightest probability helper ... Modify the top-level script and add set -vx at the 2nd line. Then you'll be able to see what was processed, where it has stopped and possibly formulate theories about why it is not processing data.
Any chance that the input file was created in a Windows environment and the cr\lf pair is messing up the expected input?
I hope this helps.
Thanks all for commenting and answering. I tried except and that did not work. So I am going to mention what worked for us. Here was our workflow - 1. At the linux prompt, type the command, it was connect() in our case. 2. Once that command is given, the script would ask for parameters for the command like port number, server etc. we had to provide that manually 3. Then we again are presented with a shell prompt with another input. In our case, we were able to provide the first command connect() at the prompt using file redirection, but the parameter passing was an issue. The solution we found was provide the parameters inside the parentheses of connect only i.e. our input file for redirection would contain - connect(). This worked for us.