WIN10 openssh in cmd "ssh xxx#xxx.xxx.xxx.xxx sh xxx.sh" error ,cant read variable normaly - bash

Im Win10 and installed the Openssh. My router is running Openwrt.The code is write via BASH
!!!The code is here!!!
flag1=1
option1_1="Its num1"
while [[ "$flag1" = "1" ]];do
read -n 1 -p "Please input num1 :" input1
case ${input1} in
1)
echo .
read -n 1 -p "Your input is: $input1,comfirm?[1/0]" comfirm1
if [[ "$comfirm1" = "1" ]];then
echo .
echo Your input is $input1,Goodbye
flag1=0
fi
;;
*)
echo Its not num1 ,please input again
flag1=1
;;
esac
done
There is a .sh file in my router and i need to run it through the steps follow:
Steps:
Win+R to open cmd.exe
type this command : ssh example#192.168.1.1 sh example.sh
And here the problem comes : it can't read the variable normally and cant output the words that i write in the file.
BUT,if i run this script use the command below,it would work normally:
Steps:
Win+R to open cmd.exe
type : ssh example#192.168.1.1
type : sh example.sh
Problems: (i have upload the video to Youtube :https://youtu.be/TPE9CjUQvxo)
It should read twich "1" and save to $input1 and $comfirm1,but it actually only read correctly when i type "11",other input will cause it loop forever.
I have noticed something , but i dont know what can do:
The things that i noticed:
When i use one command "ssh xxx#xxx.xxx.xxx.xxx sh xxx.sh",the cmd.exe window's title is still "C:\Winodws\system32\cmd.exe -ssh xxx#xxx.xxx.xxx.xxx sh test.sh".BUT when i break this command to two commands ,it change to "OpenSSH SSH client"
When i use one command,the code read -n 1 -p "xxx" wont work.it cant show the -p words or read only 1 character.
Anyone knows whats wrong and give me a advice to fix this ??

Related

how to run bash script interactively from url? [duplicate]

I have a simple Bash script that takes in inputs and prints a few lines out with that inputs
fortinetTest.sh
read -p "Enter SSC IP: $ip " ip && ip=${ip:-1.1.1.1}
printf "\n"
#check IP validation
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "SSC IP: $ip"
printf "\n"
else
echo "Enter a valid SSC IP address. Ex. 1.1.1.1"
exit
fi
I tried to upload them into my server, then try to run it via curl
I am not sure why the input prompt never kick in when I use cURL/wget.
Am I missing anything?
With the curl ... | bash form, bash's stdin is reading the script, so stdin is not available for the read command.
Try using a Process Substitution to invoke the remote script like a local file:
bash <( curl -s ... )
Your issue can be simply be reproduced by run the script like below
$ cat test.sh | bash
Enter a valid SSC IP address. Ex. 1.1.1.1
This is because the bash you launch with a pipe is not getting a TTY, when you do a read -p it is read from stdin which is content of the test.sh in this case. So the issue is not with curl. The issue is not reading from the tty
So the fix is to make sure you ready it from tty
read < /dev/tty -p "Enter SSC IP: $ip " ip && ip=${ip:-1.1.1.1}
printf "\n"
#check IP validation
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "SSC IP: $ip"
printf "\n"
else
echo "Enter a valid SSC IP address. Ex. 1.1.1.1"
exit
fi
Once you do that even curl will start working
vagrant#vagrant:/var/www/html$ curl -s localhost/test.sh | bash
Enter SSC IP: 2.2.2.2
SSC IP: 2.2.2.2
I personally prefer source <(curl -s localhost/test.sh) option. While it is similar to bash ..., the one significant difference is how processes handled.
bash will result in a new process being spun up, and that process will evoke commands from the script.
source on the other hand will use current process to evoke commands from the script.
In some cases that can play a key role. I admit that is not very often though.
To demonstrate do the following:
### Open Two Terminals
# In the first terminal run:
echo "sleep 5" > ./myTest.sh
bash ./myTest.sh
# Switch to the second terminal and run:
ps -efjh
## Repeat the same with _source_ command
# In the first terminal run:
source ./myTest.sh
# Switch to the second terminal and run:
ps -efjh
Results should look similar to this:
Before execution:
Running bash (main + two subprocesses):
Running source (main + one subprocess):
UPDATE:
Difference in use variable usage by bash and source:
source command will use your current environment. Meaning that upon execution all changes and variable declarations, made by the script, will be available in your prompt.
bash on the other hand will be running in as a different process; therefore, all variables will be discarded when process exits.
I think everyone will agree that there are benefits and drawbacks to each method. You just have to decide which one is better for your use case.
## Test for variables declared by the script:
echo "test_var3='Some Other Value'" > ./myTest3.sh
bash ./myTest3.sh
echo $test_var3
source ./myTest3.sh
echo $test_var3
## Test for usability of current environment variables:
test_var="Some Value" # Setting a variable
echo "echo $test_var" > myTest2.sh # Creating a test script
chmod +x ./myTest2.sh # Adding execute permission
## Executing:
. myTest2.sh
bash ./myTest2.sh
source ./myTest2.sh
./myTest2.sh
## All of the above results should print the variable.
I hope this helps.

Automatize the cert creation OpenVPN

I do not know why I am getting an error when I run my script with SSH, but when I run the bash from my CA server everything works fine.
I installed my VPN server based on this article https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04
I wrote a bash for the VPN creation but when I try to run it I need to SSH to the other server at some point. If I start the script with SSH in it I got an error message:
>./easyrsa: 341: set: Illegal option -o echo
My bash contain this and run from my VPN server:
sshpass -p $PASSWORD ssh username#"CA server IP" "/home/username/makevpn.sh $NAME $PASSWORD"
And makevpn.sh contain this:
>./easyrsa sign-req client $NAME
After this run it seems okay but give that error above.
I tried to read after this error and found nothing. :( Hope someone can help because I am hopeless after 4 days of troubleshooting.
Code of VPN script
#!/bin/sh
clear
read -p "Please enter the name of the new certificate : " NAME
read -p "Please enter the Password : " PASSWORD
cd /home/username/EasyRSA-3.0.7/
./easyrsa gen-req $NAME nopass
echo "gen-req done"
cp /home/username/EasyRSA-3.0.7/pki/private/$NAME.key /home/username/client-configs/keys/
echo "cp done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/reqs/$NAME.req username#192.168.1.105:/tmp
echo "scp done"
sshpass -p $PASSWORD ssh username#192.168.1.105 "/home/username/makevpn.sh $NAME $PASSWORD"
echo "ssh done"
cp /tmp/$NAME.crt /home/username/client-configs/keys/
echo "last CP done"
sudo /home/username/client-configs/make_config.sh $NAME
echo "All Done"
Code on CA server
#!/bin/sh
NAME=$1
PASSWORD=$2
cd /home/username/EasyRSA-3.0.7/
echo "CD Done"
./easyrsa import-req /tmp/$NAME.req $NAME
echo "Import-req done"
./easyrsa sign-req client $NAME
echo "Sign-req done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/issued/$NAME.crt username#192.168.1.103:/tmp
echo "Scp done"
I was just browsing the code of that easyrsa script here. This one is likely different from yours given the line for the error is 341. On the Github page, it is line 352 and it is part of a function called cleanup. It appears that this function is only attached as a trap (line 2744). Traps are used to catch signals like sigint (interrupt) which is normally sent on the terminal with ctrl+c (and may display a character like ^C). The reason the error only displays in your script is it likely causes a signal to be emitted that you would not normally receive if you ran it manually over ssh.
The error itself is really not an issue.
Code from Github:
Line 352:
(stty echo 2>/dev/null) || { (set -o echo 2>/dev/null) && set -o echo; }
Line 2744:
trap "cleanup" EXIT
It appears that line is just trying to turn terminal output of your typed characters back on (via stty echo). Sometimes programs will disable terminal output somewhere, and then re-enable it when the program finishes. However, if you were to kill the program mid way through (e.g. with ctrl+c), your program would terminate with the terminal output still disabled. This would make the terminal appear to be frozen. It would still work, but would not display the characters you type with your keyboard. The point of the trap is to ensure that terminal output is re-enabled no matter how the program exits.
More info...
At line 567 there is a function that disables echo. Looks like the point is to not show a password to the screen. If you were to kill the program during password reading, echo would remain disabled on the terminal. Likely the reason for the error has more to do with the way you are running the script. For whatever reason it causes stty echo to fail. Line 352 is assuming that the failure is due to stty echo not being a valid command. So on failure ( || ), it tries a different method (set -o echo) of enabling echo. If I try to run that on my terminal, I also get an error (bash 4.2):
-bash: set: echo: invalid option name

Syntax error after "read" only when script invoked with "bash -s <script"

I have two scripts and both are in different servers and I use these for automating a small process.
script1 starts script2 using command
ssh -i /pathToKeyFile/keyfile.pem user#server2 'bash -s < /pathToScriptFile/script2.sh'
In script2.sh I have a "case" question:
#!/bin/bash
# Ask to start up JBOSS
read -p "DB restore completed. Start JBOSS and FACADE (y/n)" startJBOSS
case "$startJBOSS" in
y|Y ) echo "Starting JBOSS and FACADE";;
n|N ) echo "Stopping here"
exit;;
* ) echo "Invalid option..."
exit;;
esac
echo "More commands here"
exit
So when I execute script1.sh it works fine and starst script2 on remote server.
But script2 fails to error
bash: line 5: syntax error near unexpected token `)'
bash: line 5: ` y|Y ) echo "Starting JBOSS and FACADE";;'
If I execute script2.sh directly from remote server it works as expected.
I also tried so that both script files are located in one server. Of cource in this case commant to start script2.sh is different, but in this case both works again as expected.
I cannot figure out why script2.sh fails when it is started from and other script located in an other server. I assume that script2.sh "code" is correct as it works when ran separately.
The problem is that read reads from stdin -- the same place your code is coming from.
Thus, instead of reading a line from the user, it reads a line from the file of source, consuming the case command, leaving the rest of the source file syntactically invalid.
Simple Answer: Don't Do That.
bash -s <filename makes sense when the <filename is coming from somewhere not accessible to the copy of bash (like the other side of the SSH connection, or a file that can only be read by a different user), but that's not the case for your example. Thus, you can just stop using the -s argument and the redirection:
ssh -i /pathToKeyFile/keyfile.pem user#server2 'bash /pathToScriptFile/script2.sh'
...or make the prompt conditional...
Another approach is to make the read conditional on there actually being a user listening at the TTY:
if [[ -t 0 ]]; then # test whether FD 0, stdin, is a TTY
read -p "DB restore completed. Start JBOSS and FACADE (y/n)" startJBOSS
else
startJBOSS=y # no TTY, so assume yes
fi
...or make the prompt read from /dev/tty, and make sure SSH passes it through.
An alternate approach is to read from /dev/tty explicitly, and then to arrange for that to be valid in the context of your script by passing appropriate arguments to ssh:
if read -p "DB restore completed. Start JBOSS and FACADE (y/n)" startJBOSS </dev/tty; then
: "read $startJBOSS from user successfully" # <- will be logged if run with set -x
else
echo "Unable to read result from user; is this being run with a TTY?" >&2
exit 1
fi
...and then, on the other side, using the -t argument to SSH, to force there to be a TTY (if one is available to SSH itself; if not, it won't have a means to read from the user out-of-band either):
ssh -t -i /pathToKeyFile/keyfile.pem user#server2 'bash -s < /pathToScriptFile/script2.sh'

Answer prompts in bash

I am often in the need of running a bash script that needs inputs from me and im trying to improve my workflow by automating this.
In my case my bash script is in need of 3 inputs from me:
What interface should i use?
1
Enter the password:
mypass
Please restart the program:
sudo bash restart
How can i make my bash script file auto input theses values? I have tried figuring this out but all the answer are about inputing yes or no.
If that is all the input your program needs, then you can simply put the inputs, one per line, in a text file, then run it like this:
$> ./yourscript.sh < yourtextfile.txt
For your example, the text file would contain
1
mypass
sudo bash restart
If you have such a script.sh:
#!/bin/bash
read -p "What intergace should i use?"$'\n' interfacenum
echo
read -p "Enter the password:"$'\n' pass
echo
read -p "Please restaart the program:"$'\n' prog
echo
echo "Values:"
for i in interfacenum pass prog; do
echo $'\t'"$i=\"${!i}\""
done
You can 'input' the values into the script using echo or printf:
echo -ne "1\nmypass\nsudo bash restart\n" | ./script.sh
You can use expect and autoexpect to achieve your task.
Let's say this is your file:
cat hello.sh
#!/usr/local/bin/bash
read -p "Select the interface: " interface
echo "interface selected: $interface"
read -p "Enter the username: " username
echo "username: $username"
You don't have to even write the scripts. You can you autoexpect to generate the script for you.
autoexpect ./hello.sh
autoexpect started, file is script.exp
Select the interface: 1
interface selected: 1
...(more input and output to generate the script)
Examine the generated script.
tail -n7 script.exp
expect -exact "Select the interface: "
send -- "1\r"
expect -exact "1\r
interface selected: 1\r
Enter the username: "
send -- "vivek\r"
expect eof
Now sit back and run the generated script
./script.exp
spawn ./hello.sh
Select the interface: 1
interface selected: 1
Enter the username: vivek
username: vivek

How do I check if a program is running in bash?

I have made a chat-script in bash and I want to check whether or not netcat is running.
I've tried pgrep but and it's working but it prints out an error in the terminal but it still keeps going like normal.
This is a part of that script:
function session()
{
echo -n "Port (default is 3333): "
read port
if [ -n "${port}" ]
then
clear
echo "Only 2 users can talk to each other simultaneously."
echo "To send a message, simply write and hit enter. Press Ctrl+C to quit."
nc -l -p ${port}
if [ pgrep "nc -l -p ${port}" ]
then
echo "${l_name} logged in to chat session"
else
clear
new
fi
else
echo "Invalid port!"
new
fi
}
Don't put prep inside [ ]. That doesn't run the prep command, it just treats the word pgrep as an argument to the test command.
You also need to use the -f option to make pgrep match the entire command line, not just the program name.
It should be
if pgrep -f "nc -l -p ${port}"
then
...
else
...
fi
Try to run script with a "-x" parameter. This shows each line that runs. Here is a description from man page:
-x : After expanding each simple command, for command, case
command, select command, or arithmetic for command, display the
expanded value of PS4, followed by the command and its expanded
arguments or associated word list.
Here is an example script:
#!/bin/bash
for i in $( ls ); do
echo item: $i
done
If you run with -x you can see each command running with a head of + sign:
$ bash -x list.sh
++ ls
+ for i in '$( ls )'
+ echo item: list.sh
item: list.sh

Resources