【问题标题】:How to transport " for remote execution?如何传输“以进行远程执行?
【发布时间】:2015-02-14 10:44:13
【问题描述】:

我正在开发一些 python 工具来配置远程系统。 一个配置步骤需要替换文本文件中的值。 我想做一个简单的

ssh whatever@where.ever sed -i -e s/property=\"true\"/property=\"false\"/g the.remote.file

但是,它不起作用。

我尝试了 shlex + 子进程,我尝试了 pxssh(无论如何我都想避免,因为与通过子进程的 ssh 调用相比,它要慢得多)。似乎无论我尝试什么,围绕真/假的引号都会在某种程度上被删除。但是引号在远程系统上的那个文件中;因此,如果在远程系统上执行的调用中没有显示引号,sed 将不执行任何操作。

当直接从我的 bash 调用 ssh 时,我可以让它工作;但从python内部......没有机会。最后,我将该字符串放入文件中;使用 scp 将该文件复制到远程系统;然后我再次使用 ssh 从那里运行它。

但仍然想知道 - 是否有一种干净、直接的方法可以“仅使用 python”来做到这一点?

(注意:我正在寻找开箱即用的解决方案;而不是需要我的用户安装其他“第三方”模块,如 paramiko。)

更新:

这……太疯狂了。我刚刚运行了这段代码(我认为它看起来与答案中给出的代码一模一样——我后来添加了 .format() 以便从发布的文本中轻松隐藏用户名/ip):

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)`

我得到:

property="true"
property="true"

这可能取决于远程系统上 sshd 的配置吗?

【问题讨论】:

  • 你试过sed -i -e 's/property="true"/property="false"/g' the.remote.file吗?顺便说一句,sed 的大多数版本都允许您为-i 选项提供扩展参数,它告诉sed 备份原始文件,例如。 sed -i~ 's/this/that/g' filename 会修改filename 并保存原来的filename~
  • 我尝试了各种方法;实际上我从 sed 表达式周围的 ' 开始。但似乎这些外部单引号、双引号、任何引号……都被吃掉了;要么通过 shlex;或通过子流程。并且不需要保留备份;以及......我知道我在做什么;-)(我们基本上是在谈论在我们的自动化测试开始之前一次性配置的测试系统)

标签: python ssh quotes


【解决方案1】:

对我来说一切都很好,我试过这个:

In [1]: import subprocess
In [2]: cmd = 'ssh ubuntu@192.168.56.101 "sed -i -e s/property=\"true\"/property=\"false\"/g ~/cfg.cfg"'
In [3]: subprocess.call(cmd, shell=True)
Out[3]: 0

由于 shell=True 可能不安全,我也尝试过:

In [4]: parts = ['ssh', 'ubuntu@192.168.56.101', '`sed -i -e s/property=\"true\"/property=\"false\"/g ~/cfg.cfg`']
In [5]: subprocess.call(parts)
Out[5]: 0

在这两种情况下,我的文件都被更改了。

更新: shlex 输出

In [27]: shlex.split(cmd)
Out[27]: 
['ssh',
 'ubuntu@192.168.56.101',
 'sed -i -e s/property=true/property=false/g ~/cfg.cfg']

另请注意,在第一种情况下,我对远程命令使用双引号,但在第二种情况下,我对命令使用反引号。

更新 2:

In [9]: subprocess.call(['ssh', 'ubuntu@192.168.56.101', 'cat ~/cfg.cfg'])
property="true"
Out[9]: 0
In [10]: subprocess.call(['ssh', 'ubuntu@192.168.56.101', '`sed -i -e s/property=\\"true\\"/property=\\"false\\"/g ~/cfg.cfg`'])
Out[10]: 0
In [11]: subprocess.call(['ssh', 'ubuntu@192.168.56.101', 'cat ~/cfg.cfg'])
property="false"
Out[11]: 0

更新 3:

In [22]: cmd = 'ssh ubuntu@192.168.56.101 \'`sed -i -e s/property=\\"true\\"/property=\\"false\\"/g ~/cfg.cfg`\''
In [23]: subprocess.call(['ssh', 'ubuntu@192.168.56.101', 'cat ~/cfg.cfg'])
property="true"
Out[23]: 0
In [24]: subprocess.call(cmd, shell=True)
Out[24]: 0
In [25]: subprocess.call(['ssh', 'ubuntu@192.168.56.101', 'cat ~/cfg.cfg'])
property="false"
Out[25]: 0
In [26]: shlex.split(cmd)
Out[26]: 
['ssh',
 'ubuntu@192.168.56.101',
 '`sed -i -e s/property=\\"true\\"/property=\\"false\\"/g ~/cfg.cfg`']

【讨论】:

  • 有趣;我想我明天必须重新审视我的代码。只是为了它:当您使用 shlex.split(cmd) 作为子进程的输入时它是否也有效?此外 - 你正在使用哪个版本的 python?
  • 我在 Python 2.7.6 和 3.4.0 上对此进行了测试
  • 请查看我对问题的更新 - 它根本不适合我?!
  • 啊..我明白了..我的代码有效,因为我没有使用双引号,所以我用property=true而不是property="true",抱歉。我进行了更多测试,我的第一个变体停止工作,但带有反引号的变体仍然可以使用添加了一些反斜杠,请参阅我的更新 2。
  • 非常感谢您解决了这个问题。我仍然考虑保留我的初始解决方案(scp 一个 bash 脚本并通过 ssh 执行);因为与这个非常复杂的表达式相比,它似乎要简单得多。但至少这是可能的;并希望对其他人有所帮助。
猜你喜欢
  • 2018-02-09
  • 2023-03-10
  • 1970-01-01
  • 2010-10-31
  • 2017-01-21
  • 2014-10-10
  • 2013-05-27
  • 2012-10-02
  • 1970-01-01
相关资源
最近更新 更多