使用 Python 通过 ssh 在远程主机上执行本地 shell 函数
Executing a local shell function on a remote host over ssh using Python
我的.profile
定义了一个函数
myps () {
ps -aef|egrep "a|b"|egrep -v "c\-"
}
我想从我的 python 脚本中执行它
import subprocess
subprocess.call("ssh user@box \"$(typeset -f); myps\"", shell=True)
找回错误
bash: -c: line 0: syntax error near unexpected token `;'
bash: -c: line 0: `; myps'
转义;结果
bash: ;: command not found
原始命令没有正确解释 myps
之前的 ;
。使用 sh -c
可以解决这个问题,但是......(请参阅下面的 Charles Duffy 评论)。
使用 single/double 引号的组合有时会使语法更易于阅读并且不易出错。考虑到这一点,运行 命令的安全方法(假设 .profile
中的函数实际上可以在 subprocess.Popen 对象启动的 shell 中访问):
subprocess.call('ssh user@box "$(typeset -f); myps"', shell=True),
另一种(不太安全)的方法是对 subshell 命令使用 sh -c
:
subprocess.call('ssh user@box "sh -c $(echo typeset -f); myps"', shell=True)
# myps is treated as a command
这似乎返回了相同的结果:
subprocess.call('ssh user@box "sh -c typeset -f; myps"', shell=True)
肯定有其他方法可以完成这些类型的任务,但是,这可能会让您了解原始命令的问题所在。
script='''
. ~/.profile # load local function definitions so typeset -f can emit them
ssh user@box ksh -s <<EOF
$(typeset -f)
myps
EOF
'''
import subprocess
subprocess.call(['ksh', '-c', script]) # no shell=True
这里有一些相关的项目:
需要在本地调用定义此函数的点文件 ,然后 您 运行 typeset -f
通过网络转储函数的定义.默认情况下,非交互式 shell 不会 运行 大多数点文件(任何由 ENV
环境变量指定的都是例外)。
在给定的示例中,这是由脚本中的 . ~/profile
命令提供的。
shell需要支持typeset
,所以必须是bash
或ksh
,而不是sh
(默认由 script=True
使用),可能由 ash
或 dash
提供,缺少此功能。
在给定的示例中,这是通过将 ['ksh', '-c']
传递给 argv 数组的前两个参数来实现的。
typeset
需要在本地是 运行,所以它不能位于第一个 script=True
以外的 argv 位置。 (举个例子:subprocess.Popen(['''printf '%s\n' "$@"''', 'This is just literal data!', '$(touch /tmp/this-is-not-executed)'], shell=True)
仅将 printf '%s\n' "$@"
计算为 shell 脚本;This is just literal data!
和 $(touch /tmp/this-is-not-executed)
作为文字数据传递,因此没有名为 /tmp/this-is-not-executed
已创建)。
在给定的示例中,这是由 not using script=True
提出的。
显式调用 ksh -s
(或 bash -s
,视情况而定)确保 shell 评估您的函数定义与 shell 您 编写了 那些函数,而不是将它们传递给 sh -c
,否则会发生。
在给定的示例中,这是由脚本中的 ssh user@box ksh -s
提供的。
我最终使用了这个。
import subprocess
import sys
import re
HOST = "user@" + box
COMMAND = 'my long command with many many flags in single quotes'
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
我的.profile
定义了一个函数
myps () {
ps -aef|egrep "a|b"|egrep -v "c\-"
}
我想从我的 python 脚本中执行它
import subprocess
subprocess.call("ssh user@box \"$(typeset -f); myps\"", shell=True)
找回错误
bash: -c: line 0: syntax error near unexpected token `;'
bash: -c: line 0: `; myps'
转义;结果
bash: ;: command not found
原始命令没有正确解释 myps
之前的 ;
。使用 sh -c
可以解决这个问题,但是......(请参阅下面的 Charles Duffy 评论)。
使用 single/double 引号的组合有时会使语法更易于阅读并且不易出错。考虑到这一点,运行 命令的安全方法(假设 .profile
中的函数实际上可以在 subprocess.Popen 对象启动的 shell 中访问):
subprocess.call('ssh user@box "$(typeset -f); myps"', shell=True),
另一种(不太安全)的方法是对 subshell 命令使用 sh -c
:
subprocess.call('ssh user@box "sh -c $(echo typeset -f); myps"', shell=True)
# myps is treated as a command
这似乎返回了相同的结果:
subprocess.call('ssh user@box "sh -c typeset -f; myps"', shell=True)
肯定有其他方法可以完成这些类型的任务,但是,这可能会让您了解原始命令的问题所在。
script='''
. ~/.profile # load local function definitions so typeset -f can emit them
ssh user@box ksh -s <<EOF
$(typeset -f)
myps
EOF
'''
import subprocess
subprocess.call(['ksh', '-c', script]) # no shell=True
这里有一些相关的项目:
需要在本地调用定义此函数的点文件 ,然后 您 运行
typeset -f
通过网络转储函数的定义.默认情况下,非交互式 shell 不会 运行 大多数点文件(任何由ENV
环境变量指定的都是例外)。在给定的示例中,这是由脚本中的
. ~/profile
命令提供的。shell需要支持
typeset
,所以必须是bash
或ksh
,而不是sh
(默认由script=True
使用),可能由ash
或dash
提供,缺少此功能。在给定的示例中,这是通过将
['ksh', '-c']
传递给 argv 数组的前两个参数来实现的。typeset
需要在本地是 运行,所以它不能位于第一个script=True
以外的 argv 位置。 (举个例子:subprocess.Popen(['''printf '%s\n' "$@"''', 'This is just literal data!', '$(touch /tmp/this-is-not-executed)'], shell=True)
仅将printf '%s\n' "$@"
计算为 shell 脚本;This is just literal data!
和$(touch /tmp/this-is-not-executed)
作为文字数据传递,因此没有名为/tmp/this-is-not-executed
已创建)。在给定的示例中,这是由 not using
script=True
提出的。显式调用
ksh -s
(或bash -s
,视情况而定)确保 shell 评估您的函数定义与 shell 您 编写了 那些函数,而不是将它们传递给sh -c
,否则会发生。在给定的示例中,这是由脚本中的
ssh user@box ksh -s
提供的。
我最终使用了这个。
import subprocess
import sys
import re
HOST = "user@" + box
COMMAND = 'my long command with many many flags in single quotes'
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()