Reputation: 140505
I am working on some python tooling to configure remote systems. One configuration step requires to replace values in a text file. I thought to do a simple
ssh [email protected] sed -i -e s/property=\"true\"/property=\"false\"/g the.remote.file
But well, it doesnt work.
I tried shlex + subprocess, I tried pxssh (which I would like to avoid anyway, as it is much slower compared to a ssh call via subprocess). It seems that whatever I try, the quotes around true/false are removed at some level. But the quotes are in that file on the remote system; so sed will do nothing if the quotes are not showing up in the call that is executed on the remote system.
I could get it working when invoking ssh directly from my bash; but from within python ... no chance. In the end, I put that string into a file; use scp to copy that file to the remote system; and then I ran it from there using ssh again.
But still wondering - is there a clean, straight forward way to do this "just using python"?
(Note: I am looking for solutions that work out of box; not something that requires my users to install other "third party" modules like paramiko.)
Update:
This is ... crazy. I just ran this code (which I think looks exactly like the code that is given in the answer --- I added the .format() afterwards to easily hide username/ip from the posted text):
cmd_str= 'ssh {} "cat ~/prop"'.format(target)
subprocess.call(cmd_str, shell=True)
cmd_str= 'ssh {} "sed -i -e s/property=\"true\"/property=\"false\"/g ~/prop"'.format(target)
subprocess.call(cmd_str, shell=True)
cmd_str= 'ssh {} "cat ~/prop"'.format(target)
subprocess.call(cmd_str, shell=True)`
and I get:
property="true"
property="true"
Could that depend on the configuration of the sshd on the remote system?
Upvotes: 1
Views: 87
Reputation: 641
Everything worked fine for me, I tried this:
In [1]: import subprocess
In [2]: cmd = 'ssh [email protected] "sed -i -e s/property=\"true\"/property=\"false\"/g ~/cfg.cfg"'
In [3]: subprocess.call(cmd, shell=True)
Out[3]: 0
and as shell=True can be unsafe I also tried this:
In [4]: parts = ['ssh', '[email protected]', '`sed -i -e s/property=\"true\"/property=\"false\"/g ~/cfg.cfg`']
In [5]: subprocess.call(parts)
Out[5]: 0
In both cases my file was changed.
UPDATE: shlex output
In [27]: shlex.split(cmd)
Out[27]:
['ssh',
'[email protected]',
'sed -i -e s/property=true/property=false/g ~/cfg.cfg']
Also note, In the first case I use double quotes for the remote command but in the second case I use back quotes for the command.
UPDATE 2:
In [9]: subprocess.call(['ssh', '[email protected]', 'cat ~/cfg.cfg'])
property="true"
Out[9]: 0
In [10]: subprocess.call(['ssh', '[email protected]', '`sed -i -e s/property=\\"true\\"/property=\\"false\\"/g ~/cfg.cfg`'])
Out[10]: 0
In [11]: subprocess.call(['ssh', '[email protected]', 'cat ~/cfg.cfg'])
property="false"
Out[11]: 0
UPDATE 3:
In [22]: cmd = 'ssh [email protected] \'`sed -i -e s/property=\\"true\\"/property=\\"false\\"/g ~/cfg.cfg`\''
In [23]: subprocess.call(['ssh', '[email protected]', 'cat ~/cfg.cfg'])
property="true"
Out[23]: 0
In [24]: subprocess.call(cmd, shell=True)
Out[24]: 0
In [25]: subprocess.call(['ssh', '[email protected]', 'cat ~/cfg.cfg'])
property="false"
Out[25]: 0
In [26]: shlex.split(cmd)
Out[26]:
['ssh',
'[email protected]',
'`sed -i -e s/property=\\"true\\"/property=\\"false\\"/g ~/cfg.cfg`']
Upvotes: 1