How to pass command in command to pexpext in python - linux

I need in python execute this command and enter password from keyboard, this is works:
import os
cmd = "cat /home/user1/.ssh/id_rsa.pub | ssh user2#host.net \'cat >> .ssh/authorized_keys\' > /dev/null 2>&1"
os.system(cmd)
As you can see I want append public key to remote host via ssh.
See here: equivalent-of-ftp-put-and-append-in-scp and here: copy-and-append-files-to-a-remote-machine-cat-error
Of course I want it do it without user input I've try pexpect and I think command is to weird for it:
import pexpect
child = pexpect.spawn(command=cmd, timeout=10, logfile=open('debug.txt', 'a+'))
matched = child.expect(['Password:', pexpect.EOF, pexpect.TIMEOUT])
if matched == 0:
child.sendline(passwd)
in debug.txt:
ssh-rsa AAAA..........vcxv233x5v3543sfsfvsv user1#host1
/bin/cat: |: No such file or directory
/bin/cat: ssh: No such file or directory
/bin/cat: user2#host.net: No such file or directory
/bin/cat: cat >> .ssh/authorized_keys: No such file or directory
/bin/cat: >: No such file or directory
/bin/cat: 2>&1: No such file or directory
I see two solution:
fix command for pexpect, that it recognize whole string as one command or,
inject/write passwd to stdin as fake user, but how!?!?

From the pexpect docs:
Remember that Pexpect does NOT interpret shell meta characters such as
redirect, pipe, or wild cards (>, |, or *). This is a
common mistake. If you want to run a command and pipe it through
another command then you must also start a shell. For example::
child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
child.expect(pexpect.EOF)

That worked for me:
command = "/bin/bash -c \"cat /home/user1/.ssh/id_rsa.pub | ssh user2#host.net \'cat >> ~/.ssh/authorized_keys\' > /dev/null 2>&1\""
child = spawn(command=command, timeout=5)

Related

Passing parameter from one batch file to another not working [duplicate]

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"

PLINK command executes but no file created

I have wrote a bash file so If an user select a specific option then on a linux server a specific .sh file will execute.
For example:
If a user presses 1:
for %%? in (1) do if /I "%C%"=="%%?" goto print
:print
CLS
start C:\tools\PLINK.EXE -ssh -pw <password> -t <user>#10.111.11.111 "echo <password> | sudo -S /var/www/test/test.sh"
I can see the shell script starting but on my linux server "test.sh" has commands to create a .txt file.
echo $NAME "test" >> test.txt (for example)
My question now is... why is it if I run test.sh on the linux server directly the test.txt has been succesfully created.
If I run test.sh trough my windows batch file, I can see the command is activated but no test.txt file is created on the linux server.
Thank you for the help!
Either the test.txt will be in your HOME directory or you can give the entire path along with the test.txt to verify.

Read script file sh [duplicate]

This question already has answers here:
Are shell scripts sensitive to encoding and line endings?
(14 answers)
Closed 4 years ago.
I have a shell script with a command that seems like it should work, but instead it fails with an odd wrapped/truncated/corrupted error message. Example:
$ ls -l myfile
-rw-r----- 1 me me 0 Aug 7 12:36 myfile
$ cat myscript
ls -l myfile
$ bash myscript
: No such file or directory
The file clearly exist, but even if I didn't, this is the kind of error message I would normally get:
$ ls -l idontexist
ls: cannot access idontexist: No such file or directory
Notice how it includes the tool name ls, a message string and the filename while mine does not.
Here's what I get if I try to use mysql instead. The error message looks like it's been wrapped, and now starts with a quote:
Command: mysql -h myhost.example.com
Expected: ERROR 2005 (HY000): Unknown MySQL server host 'myhost.example.com' (0)
Actual: ' (0) 2005 (HY000): Unknown MySQL server host 'myhost.example.com
And here's my trivial ssh command that should work, or at least give a normal error message, but which instead is wrapped to start with a colon and ends with strange clobbering:
Command: ssh myhost
Expected: ssh: Could not resolve hostname myhost: Name or service not known
Actual: : Name or service not knownname myhost
Why does this happen, and how do I fix it?
TL;DR: Your script or data has Windows style CRLF line endings.
Convert to Unix style by deleting the carriage returns.
How do I check if my script or data has carriage returns?
They're detectable as ^M in the output of cat -v yourscript:
$ cat -v myscript
ls -l myfile^M
If your script doesn't have them, your data might -- especially if reading from ini/csv files or curl:
hostname=$(curl https://example.com/loginhost.txt)
ssh "$hostname" # Shows strange error
echo "$hostname" | cat -v # Shows myhost^M
How do I remove them?
Set your editor to save the file with Unix line endings, aka "line terminators" or "end-of-line characters", and resave it.
You can also remove them from a command line with dos2unix yourscript or cat yourscript | tr -d '\r' > fixedscript.
If found in your data, you can pipe your source through tr -d '\r':
hostname=$(curl https://example.com/loginhost.txt | tr -d '\r')
Why do carriage returns cause strange error messages?
The "carriage return" character, aka CR or \r, causes the cursor to move to the start of the line, and continue printing from there. In other words, it starts overwriting the line from the start. This is why they wrap strangely:
Intended: ssh: Could not resolve hostname myhost\r: Name or service not known
Written: ssh: Could not resolve hostname myhost\r
Overwritten: : Name or service not known
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Result: : Name or service not knownname myhost

How to run a command in bash script from another directory [duplicate]

This question already has answers here:
Are shell scripts sensitive to encoding and line endings?
(14 answers)
Closed 4 years ago.
I have a shell script with a command that seems like it should work, but instead it fails with an odd wrapped/truncated/corrupted error message. Example:
$ ls -l myfile
-rw-r----- 1 me me 0 Aug 7 12:36 myfile
$ cat myscript
ls -l myfile
$ bash myscript
: No such file or directory
The file clearly exist, but even if I didn't, this is the kind of error message I would normally get:
$ ls -l idontexist
ls: cannot access idontexist: No such file or directory
Notice how it includes the tool name ls, a message string and the filename while mine does not.
Here's what I get if I try to use mysql instead. The error message looks like it's been wrapped, and now starts with a quote:
Command: mysql -h myhost.example.com
Expected: ERROR 2005 (HY000): Unknown MySQL server host 'myhost.example.com' (0)
Actual: ' (0) 2005 (HY000): Unknown MySQL server host 'myhost.example.com
And here's my trivial ssh command that should work, or at least give a normal error message, but which instead is wrapped to start with a colon and ends with strange clobbering:
Command: ssh myhost
Expected: ssh: Could not resolve hostname myhost: Name or service not known
Actual: : Name or service not knownname myhost
Why does this happen, and how do I fix it?
TL;DR: Your script or data has Windows style CRLF line endings.
Convert to Unix style by deleting the carriage returns.
How do I check if my script or data has carriage returns?
They're detectable as ^M in the output of cat -v yourscript:
$ cat -v myscript
ls -l myfile^M
If your script doesn't have them, your data might -- especially if reading from ini/csv files or curl:
hostname=$(curl https://example.com/loginhost.txt)
ssh "$hostname" # Shows strange error
echo "$hostname" | cat -v # Shows myhost^M
How do I remove them?
Set your editor to save the file with Unix line endings, aka "line terminators" or "end-of-line characters", and resave it.
You can also remove them from a command line with dos2unix yourscript or cat yourscript | tr -d '\r' > fixedscript.
If found in your data, you can pipe your source through tr -d '\r':
hostname=$(curl https://example.com/loginhost.txt | tr -d '\r')
Why do carriage returns cause strange error messages?
The "carriage return" character, aka CR or \r, causes the cursor to move to the start of the line, and continue printing from there. In other words, it starts overwriting the line from the start. This is why they wrap strangely:
Intended: ssh: Could not resolve hostname myhost\r: Name or service not known
Written: ssh: Could not resolve hostname myhost\r
Overwritten: : Name or service not known
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Result: : Name or service not knownname myhost

pipe stderr to syslog inside automated ftp script

I'm using simple script to automate ftp. The script looks like this:
ftp -nv $FTP_HOST<<END_FTP
user $FTP_USER $FTP_PASS
binary
mkdir $REMOTE_DIR
cd $REMOTE_DIR
lcd $LOCAL
put $FILE
bye
END_FTP
But I would like to pipe STDERR to the syslog and STDOUT to a logfile. Normally I would do something like that: ftp -nv $FTP_HOST 1>>ftp.log | logger<<END_FTP but in this case that won't work because of <<END_FTP. How should I do it properly to make the script work? Note that I want to redirect only output from the FTP command inside my script and not the whole script.
This works without using a temp file for the error output. The 2>&1 sends the error output to where standard output is going — which is the pipe. The >> changes where standard output is going — which is now the file — without changing where standard error is going. So, the errors go to logger and the output to ftp.log.
ftp -nv $FTPHOST <<END_FTP 2>&1 >> ftp.log | logger
user $FTP_USER $FTP_PASS
binary
mkdir $REMOTE_DIR
cd $REMOTE_DIR
lcd $LOCAL
put $FILE
bye
END_FTP
How about:
exec > mylogfile; exec 2> >(logger -t myftpscript)
in front of you ftp script
Another way of doing this I/O redirection is with the { ... } operations, thus:
{
ftp -nv $FTPHOST <<END_FTP >> ftp.log
user $FTP_USER $FTP_PASS
binary
mkdir $REMOTE_DIR
cd $REMOTE_DIR
lcd $LOCAL
put $FILE
bye
END_FTP
# Optionally other commands here...stderr will go to logger too
} 2>&1 | logger
This is often the best mechanism when more than one command, but not all commands, need the same I/O redirection.
In context, though, I think this solution is the best (but that's someone else's answer, not mine):
ftp -nv $FTPHOST <<END_FTP 2>&1 >> ftp.log | logger
...
END_FTP
Why not create a netrc file and let that do your login and put the file for you.
The netrc file will let you login and allow you to define an init macro that will make the needed directory and put the file you want over there. Most ftp commands let you specify which netrc file you'd like to use, so you could use various netrc files for various purposes.
Here's an example netrc file called my_netrc:
machine ftp_host
user ftp_user
password swordfish
macrodef init
binary
mkdir my_dir
cd my_dir
put my_file
bye
Then, you could do this:
$ ftp -v -Nmy_netrc $FTPHOST 2>&1 >> ftp.log | logger

Resources