I'm trying to write a batch file to run in Windows 10 Pro that will use Plink to establish an SSH session to a remote server and execute some commands. Everything works well, except for whatever reason I end up with extra line feeds with each ECHO command I pipe in. Normally, this isn't an issue, until the command I'm running requires some specific user feedback, namely, pressing Y to confirm an action. Since it receives the extra line feed after testing STSTest command and before receiving the Y character, it throws an error.
Here's my batch script:
set PATH=C:\Program Files\PuTTY;%PATH%
set TestNum=%1
(
TIMEOUT /t 1 > nul
ECHO cd /usr/bin/core/test
ECHO rm STS_*.txt
ECHO rm STS_T1_Test%TestNum%.txt
ECHO ./STSTest --T 2 --i %TestNum%
TIMEOUT /t 1 > nul
ECHO Y
TIMEOUT /t 1 > nul
ECHO exit
) | plink -ssh 192.168.1.20 -l root -pw ***
Does anybody have an idea on how to eliminate that extra line feed so that Y is entered in the correct order after the STSTest command is entered?
Here's a simpler example demonstrating what I'm fighting. If I define this simple batch file:
(
TIMEOUT /t 1 > nul
ECHO cd /
ECHO cd usr
ECHO cd bin
ECHO cd core
ECHO cd test
TIMEOUT /t 1 > nul
ECHO exit
) | plink -ssh 192.168.1.20 -l root -pw ***
The results from the command window look like:
Last login: Wed Jul 29 23:53:30 2020 from 192.168.1.7
root#core-A:~# cd /
root#core-A:/#
root#core-A:/# cd usr
root#core-A:/usr#
root#core-A:/usr# cd bin
root#core-A:/usr/bin#
root#core-A:/usr/bin# cd core
root#core-A:/usr/bin/core#
root#core-A:/usr/bin/core# cd test
root#core-A:/usr/bin/core/test#
root#core-A:/usr/bin/core/test# exit
I get an extra line feed after every ECHO command.
When you are executing plink without any command on its command-line, plink starts an interactive terminal session. That has lot of unwanted side effects. Including those that you face.
Add -T switch to plink command line to avoid that:
(
...
) | plink -T -ssh 192.168.1.20 -l root -pw ***
Another option is doing everything on the server-side and specifying full command on the plink commandline (in this case, you will also need to add the -batch switch):
plink -ssh 192.168.1.20 -l root -pw *** -batch "cd /usr/bin/core/test && rm STS_*.txt && rm STS_T1_Test%TestNum%.txt && (echo Y | ./STSTest --T 2 --i %TestNum%)"
Or some combination of both these methods.
Similar questions:
Windows batch scripting: SSH with Plink showing strange sequences in output
Executing command using Plink does not work, but does in PuTTY
Script via Plink in .bat behaves differently
A batch file echo uses the Windows line ending (carriage return+line feed).
Combine the newline hack with the no line ending hack:
#echo off
REM don't remove blank lines below
set NLM=^
set NL=^^^%NLM%%NLM%^%NLM%%NLM%
(
<nul set /P=foo%NL%
<nul set /P=foo%NL%bar%NL%
) > test.txt
and test.txt becomes (hex output)
66 6F 6F 0A 66 6F 6F 0A 62 61 72 0A foo.foo.bar.
Related
I need to execute a shell script remotely inside the Linux box from Windows
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit
fi
echo "$1"
Here is the command I ran from Windows command prompt
cmd> plink.exe -ssh username#host -pw gbG32s4D/ -m C:\myscript.sh 5
I am getting output as
"Illegal number of parameters"
Is there any way I can pass command line parameter to shell script which will execute on remote server?
You misunderstand how the -m switch works.
It is just a way to make plink load the commands to send to the server from a local file.
The file is NOT uploaded and executed on the remote server (with arguments).
It's contents is read locally and sent to the server and executed there as if you typed it on a (remote) command line. You cannot give it arguments.
A workaround is to generate the file on the fly locally before running plink from a batch file (say run.bat):
echo echo %1 > script.tmp
plink.exe -ssh username#host -pw gbG32s4D/ -m script.tmp
Then run the batch file with the argument:
run.bat 5
The above will make the script execute echo 5 on the server.
If the script is complex, instead of assembling it locally, have it ready on the server (as #MarcelKuiper suggested) and execute just the script via Plink.
plink.exe -ssh username#host -pw gbG32s4D/ "./myscript.sh %1"
In this case, as we execute just one command, you can pass it on Plink command line, including the arguments. You do not have to use the -m switch with a (temporary) file.
I triggered the Shell script in "commands.txt" from Plink which worked for me like a charm with below method I tried:
You can define your script as an one liner using && in a file (I defined in one liner)
You need to run your command in <
Note: Use first EOF in quote like <<'EOF' but not the last one. Else you will see you code will behave weirdly.
Please see below.
Example:
sudo -i <<'EOF'
<your script here>
EOF
Then, finally run it using Plink:
plink -ssh username#hostname -pw password -m commands.txt
Have you tried putting the command and argument in quotes:
i.e. -m "C:\myscript.sh 5"
I would like to ask a question about how to apply PuTTY and control its return values. My setup is like this.
There's a xxxxx.bat file which contains PuTTY call with a ssh connection in the likes of:
putty.ext ssh 10.10.10.10 -l xxxx -pw yyyy -t -m wintest.txt
The file wintest.txt contains:
echo "wintest.txt: Before execute..."
/home/tede/n55115/PD/winlinux/RUN.lintest.bsh
echo "wintest.txt: After execute..."
echo $?
The file lintest.bsh contains various commands, what interests me is to be able to capture the return value of a specific command in the .bsh file, and call on that value from the bat file, to add it into an if loop with a warning, ie if $? (or %ERRORLEVEL - I don't know what would work) then BLABLA
I've read a lot of posts about this, but frankly this is my first time doing anything with .bat files so its all slightly confusing.
First, do not use PuTTY for automation, use Plink (PuTTY command-line connection tool).
But even Plink cannot propagate the remote command exit code.
You can have the remote script print the exit code on the last line of its output (what you are doing already with the echo $?) and have the batch file parse the exit code:
#echo off
plink.exe putty.ext ssh 10.10.10.10 -l xxxx -pw yyyy -t -m wintest.txt > output.txt 2>&1
for /F "delims=" %%a in (output.txt) do (
echo %%a
set "SHELL_EXIT_CODE=%%a"
)
if %SHELL_EXIT_CODE% gtr 0 (
echo Error %SHELL_EXIT_CODE%
) else (
echo Success
)
But of course, you have to fix your script to return the exit code you want (the current code returns exit code of the previous echo command):
echo "wintest.txt: Before execute..."
/home/tede/n55115/PD/winlinux/RUN.lintest.bsh
EXIT_CODE=$?
echo "wintest.txt: After execute..."
echo $EXIT_CODE
I need to execute a shell script remotely inside the Linux box from Windows
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit
fi
echo "$1"
Here is the command I ran from Windows command prompt
cmd> plink.exe -ssh username#host -pw gbG32s4D/ -m C:\myscript.sh 5
I am getting output as
"Illegal number of parameters"
Is there any way I can pass command line parameter to shell script which will execute on remote server?
You misunderstand how the -m switch works.
It is just a way to make plink load the commands to send to the server from a local file.
The file is NOT uploaded and executed on the remote server (with arguments).
It's contents is read locally and sent to the server and executed there as if you typed it on a (remote) command line. You cannot give it arguments.
A workaround is to generate the file on the fly locally before running plink from a batch file (say run.bat):
echo echo %1 > script.tmp
plink.exe -ssh username#host -pw gbG32s4D/ -m script.tmp
Then run the batch file with the argument:
run.bat 5
The above will make the script execute echo 5 on the server.
If the script is complex, instead of assembling it locally, have it ready on the server (as #MarcelKuiper suggested) and execute just the script via Plink.
plink.exe -ssh username#host -pw gbG32s4D/ "./myscript.sh %1"
In this case, as we execute just one command, you can pass it on Plink command line, including the arguments. You do not have to use the -m switch with a (temporary) file.
I triggered the Shell script in "commands.txt" from Plink which worked for me like a charm with below method I tried:
You can define your script as an one liner using && in a file (I defined in one liner)
You need to run your command in <
Note: Use first EOF in quote like <<'EOF' but not the last one. Else you will see you code will behave weirdly.
Please see below.
Example:
sudo -i <<'EOF'
<your script here>
EOF
Then, finally run it using Plink:
plink -ssh username#hostname -pw password -m commands.txt
Have you tried putting the command and argument in quotes:
i.e. -m "C:\myscript.sh 5"
I have problem executing a simple script in bash. The script is like this:
#! /bin/sh
read -p 'press [ENTER] to continue deleting line'
sudo sed -ie '$d' /home/hpccuser/.profile
and when I execute the script with ./script the output is like this:
press [ENTER] to continue deleting line./script: 3: read: arg count
[sudo] password for user
I run the read command directly in terminal (copy and paste from script to terminal) and it works fine; it waits for an ENTER to be hit (just like a pause).
Because your script starts with #!/bin/sh rather than #!/bin/bash, you aren't guaranteed to have bash extensions (such as read -p) available, and can rely only on standards-compliant functionality.
See the relevant standards document for a list of functionality guaranteed to be present in read.
In this case, you'd probably want two lines, one doing the print, and the other doing the read:
printf 'press [ENTER] to continue deleting...'
read _
You can do this with echo command too!:
echo "press [ENTER] to continue deleting line"
read continue
If you use pipe to redirect contents to your function/script it will run your command in a sub-shell and set stdin (0) to a pipe, which can be checked by
$ ls -l /dev/fd/
lr-x------ 1 root root 64 May 27 14:08 0 -> pipe:[2033522138]
lrwx------ 1 root root 64 May 27 14:08 1 -> /dev/pts/11
lrwx------ 1 root root 64 May 27 14:08 2 -> /dev/pts/11
lr-x------ 1 root root 64 May 27 14:08 3 -> /proc/49806/fd
And if you called read/readarray/... command in that function/script, the read command would return immediately whatever read from that pipe as the stdin has been set to that pipe rather than the tty, which explained why read command didn't wait for input. To make read command wait for input in such case you have to restore stdin to tty by exec 0< /dev/tty before the call to read command.
read -p " Ici mon texte " continue
it works on raspbian
Seems I'm late to the party, but echo -n "Your prompt" && sed 1q does the trick on a POSIX-compliant shell.
This prints a prompt, and grabs a line from STDIN.
Alternatively, you could expand that input into a variable:
echo -n "Your prompt"
YOUR_VAR=$(sed 1q)
I'm trying to create batch file which should have this commands:
cd "c:\Program files\NuSMV\2.5.2\bin\"
NuSMV -int short.smv
go
pick_state -r
print_current_state -v
simulate -r 3
show_traces -t
show_traces -v
The problem I encounter is this: after the second line is executed, NuSMV.exe runs in cmd and rest of the commands don't execute until I exit NuSMV, but I want to run commands 3-8 in NuSMV. What do I need to change in my .bat file. Thanks.
Put commands 3-8 in a text file (eg., cmds.txt), then run NuSMV as follows:
NuSMV -int short.smv -source cmds.txt
From the manual (nusmv.pdf) p.48:
It is also possible to make NUSMV read
and execute a sequence of commands
from a file, through the command line
option -source:
system prompt> NuSMV -source cmd file
Completing Vik answer, you can create the NUSMV commands file in the same BAT file
#echo off
pushd "c:\Program files\NuSMV\2.5.2\bin\"
echo go >"%TEMP%\cmds.txt"
echo pick_state -r >>"%TEMP%\cmds.txt"
echo print_current_state -v >>"%TEMP%\cmds.txt"
echo simulate -r 3 >>"%TEMP%\cmds.txt"
echo show_traces -t >>"%TEMP%\cmds.txt"
echo show_traces -v >>"%TEMP%\cmds.txt"
NuSMV -int short.smv -source "%TEMP%\cmds.txt"
del "%TEMP%\cmds.txt"
popd
Additionally I would recommend you to not change the current directory to NuSMV directory. Either editing the PATH, or just specifying NuSMV with its full path. In both cases you should then invoke the BAT from the current directory where short.smv is located.C
#echo off
echo go >"%TEMP%\cmds.txt"
echo pick_state -r >>"%TEMP%\cmds.txt"
echo print_current_state -v >>"%TEMP%\cmds.txt"
echo simulate -r 3 >>"%TEMP%\cmds.txt"
echo show_traces -t >>"%TEMP%\cmds.txt"
echo show_traces -v >>"%TEMP%\cmds.txt"
"c:\Program files\NuSMV\2.5.2\bin\NuSMV" -int short.smv -source "%TEMP%\cmds.txt"
del "%TEMP%\cmds.txt"