Writing shell script using another shell script - shell

I'm trying to automate running of a shell script that would take some user inputs at various points of its execution.
The basic logic that I've in my mind is copied below, but this is only for one input. I wanna run it recursively until the shell prompt is received after the original script completes its execution. I said recursively because, the question that prompts for an input and the input itself will be the same all the time.
#!/usr/bin/expect
spawn new.sh $1
expect "Please enter input:"
send "my_input"
Sharing any short-cut/simple method to achieve this will be highly appreciated.

You don't need expect to do this - read can read from a pipe as well as from user input, so you can pass the input through a pipe to your script. Example script:
#!/bin/bash
read -p "Please enter input: " input
echo "Input: $input"
Running the script prompts for input as normal, but if you pipe to it:
$ echo "Hello" | sh my_script.sh
Input: Hello
You said that your input is always the same - if so, then you can use yes (which just prints a given string over and over) to pass your script the input repeatedly:
yes "My input" | sh my_script.sh
This would run my_script.sh, any read commands within the script will read "My input".

Related

Failed to transfer some file with mput on sftp

I have a problem with my script that allows me to transfer several excel files with SFTP, every day some file is not transmitted, it's not a problem of file content or name.
Here is the code:
sshpass -f password/pass_sftp sftp $SFTP_USER#$SFTP_HOST << EOF
cd /store/availability
mput *.csv
bye
EOF
Do you have any idea what it could be ?
The proper form of use for the command, for cat to use "EOF" as the pattern to indicate end of input, is to use the combination "<<-" followed by the {string}.
Your first line should read as:
sshpass -f password/pass_sftp sftp $SFTP_USER#$SFTP_HOST <<-EOF
The heredoc construct is sometimes misleading with interactive programs as you may face synchronization problems. That is to say that the interactive programs may not accept data until it prompts it or it can flush out the data received so far before displaying its prompt. This is why using a utility like expect which simulates an operator in front of the interactive tool is more robust.
Let's consider the following interactive program example which prompts for a first and a last name and simulates some activity between the two inputs:
#!/bin/bash
echo "Enter your first name: "
read fname
# Do some actions here and make some cleanup in the input buffer
read -t 1 -n 1000 garbage
echo "Enter your last name: "
read lname
echo you have entered $fname $lname
If we run it interactively, it works fine:
$ ./interact.sh
Enter your first name:
azerty
Enter your last name:
qwerty
you have entered azerty qwerty
But if we run it with an heredoc, it fails because the second input arrives too early:
$ ./interact.sh <<EOF
> azerty
> qwerty
> EOF
Enter your first name:
Enter your last name:
you have entered azerty
The heredoc does not provide the ability to synchronize with the displayed prompts.
With an expect script, it is possible to wait for the display of the prompts before entering the answers as a human being would do. Let's consider the following to automate interact.sh:
#!/usr/bin/expect
set timeout -1
spawn ./interact.sh
expect "first name:"
send "azerty\n"
expect "last name:"
send "qwerty\n"
expect eof
The execution result is the same as if a human interacted:
$ ./exp
spawn ./interact.sh
Enter your first name:
azerty
Enter your last name:
qwerty
you have entered azerty qwerty

How to get the command output in variable?

I executed the below code as .sh file and getting the result as expected. Now I need to store the output of the "send" command and do things further.
I have done the below bash code and now I am keeping the output in a file:
#!/usr/bin/expect -f
spawn iroot
expect ".* password for"
sleep 3
send "password\r"
sleep 5
send "dmidecode -t system | grep Manufacturer > /tmp/manfacdetails.txt\r"
send "exit\r"
interact
How can I do that?
It seems that you are using iroot to obtain root access to a phone and issuing a command as root.
I am assuming here that the command you already have is noninteractive, and produces the output you want if you take out the redirection to a file, without any human interaction.
Then, the simple matter of capturing its output is covered by the common FAQ How to set a variable to the output of a command in Bash?
#!/bin/bash
manufacturer=$(expect <<\____HERE)
spawn iroot
expect ".* password for"
sleep 3
send "password\r"
sleep 5
send "dmidecode -t system | grep Manufacturer\r"
send "exit\r"
interact
____HERE
if [ "$manufacturer" = "Motor Ola" ]; then
ola=1
fi
# Maybe you'll prefer case over if, though
case $manufacturer in
"Samsung" | "LG" ) korean=1 ;;
"Apple")
echo "$0: You're kidding, right?" >&2
exit 127;;
*) echo "$0: Unknown manufacturer $manufacturer" >&2
exit 1;;
esac
If this doesn't work for you then Use expect in bash script to provide password to SSH command has some variants you might want to try.
You also seem to be confused about the nature of scripts. Any executable file which has a shebang as its first line will be executable by whatever interpreter is specified there. Mine has /bin/bash so this is a shell script and more specifically a Bash script, while yours has expect as its interpreter, so it's an Expect script. You also commonly have Awk scripts and Perl scripts and Python scripts (and less commonly but not at all uncommonly scripts in many, many other languages).
As already mentioned, Expect is also a scripting language, and it is possible that you would like for yours to remain an Expect script, rather than a shell script with an embedded Expect script snippet. Perhaps then see expect: store output of a spawn command into variable
The name of the file which contains the script can be anything, but the standard recommendation is to not give it an extension -- Unix doesn't care, and human readers will be confounded if your .sh file is an Expect script (as it currently is).
Perhaps tangentially see also Difference between sh and bash as well as http://shellcheck.net/ which you can use to diagnose syntax errrors in your (shell) scripts.

Piping multiple commands to bash, pipe behavior question

I have this command sequence that I'm having trouble understanding:
[me#mine ~]$ (echo 'test'; cat) | bash
echo $?
1
echo 'this is the new shell'
this is the new shell
exit
[me#mine ~]$
As far as I can understand, here is what happens:
A pipe is created.
stdout of echo 'test' is sent to the pipe.
bash receives 'test' on stdin.
echo $? returns 1, which is what happens when you run test without args.
cat runs.
It is copying stdin to stdout.
stdout is sent to the pipe.
bash will execute whatever you type in, but stderr won't get printed to the screen (we used |, not |&).
I have three questions:
It looks like, even though we run two commands, we use the same pipe and bash process for both commands. Is that the case?
Where do the prompts go?
When something like cat uses stdin, does it take exclusive ownership of stdin as long as the shell runs, or can other things use it?
I suspect I'm missing some detail with ttys, but I'm not sure. Any help or details or man excerpt appreciated!
So...
Yes, there's a single pipe sending commands to a single instance of bash. Note:
$ echo 'date "+%T hello $$"; sleep 1; date "+%T world $$"' | bash
22:18:52 hello 72628
22:18:53 world 72628
There are no prompts. From the man page:
An interactive shell is one started without non-option arguments (unless -s is specified) and without the -c option whose standard input and error are both connected to terminals. PS1 is set and $- includes i if bash is interactive.
So a pipe is not an interactive shell, and therefore has no prompt.
Stdin and stdout can only connect to one thing at a time. cat will take stdin from the process that ran it (for example, your interactive shell) and send its stdout through the pipe to bash. If you need multiple things to be able to submit to the stdin of that cat, consider using a named pipe.
Does that cover it?

How to put ICP cluster login in shell script [duplicate]

I have a script that calls an application that requires user input, e.g. run app that requires user to type in 'Y' or 'N'.
How can I get the shell script not to ask the user for the input but rather use the value from a predefined variable in the script?
In my case there will be two questions that require input.
You can pipe in whatever text you'd like on stdin and it will be just the same as having the user type it themselves. For example to simulating typing "Y" just use:
echo "Y" | myapp
or using a shell variable:
echo $ANSWER | myapp
There is also a unix command called "yes" that outputs a continuous stream of "y" for apps that ask lots of questions that you just want to answer in the affirmative.
If the app reads from stdin (as opposed to from /dev/tty, as e.g. the passwd program does), then multiline input is the perfect candidate for a here-document.
#!/bin/sh
the_app [app options here] <<EOF
Yes
No
Maybe
Do it with $SHELL
Quit
EOF
As you can see, here-documents even allow parameter substitution. If you don't want this, use <<'EOF'.
the expect command for more complicated situations, you system should have it. Haven't used it much myself, but I suspect its what you're looking for.
$ man expect
http://oreilly.com/catalog/expect/chapter/ch03.html
I prefer this way: If You want multiple inputs... you put in multiple echo statements as so:
{ echo Y; Y; } | sh install.sh >> install.out
In the example above... I am feeding two inputs into the install.sh script. Then... at the end, I am piping the script output to a log file to be archived and viewed for later.

linux - bash: pipe _everything_ to a logfile

In an interactive bash script I use
exec > >(tee -ia logfile.log)
exec 2>&1
to write the scripts output to a logfile. However, if I ask the user to input something this is not written to this file:
read UserInput
Also, I issue commands with $UserInput as parameter. These command are also not written to the logfile.
The logfile should contain everything my script does, i.e. what the user entered interactively and also the resulting commands along with their output.
Of course I could use set -x and/or echo "user input: "$UserInput, but this would also be sent to the "screen". I dont want to read anything else on the screen except what my script or the commands echo.
How can this be done?

Resources