我正在尝试使用 os.system
在 python 脚本中运行 ssh 命令添加 0
在远程服务器中使用 ssh
的完全匹配字符串的末尾和 sed
.
我有一个名为 nodelist
的文件在远程服务器中,它是一个看起来像这样的列表。
test-node-1
test-node-2
...
test-node-11
test-node-12
test-node-13
...
test-node-21
我想用sed做如下修改,我要搜索test-node-1
,并且当找到完全匹配时,我想在末尾添加一个 0,文件必须最终看起来像这样。test-node-1 0
test-node-2
...
test-node-11
test-node-12
test-node-13
...
test-node-21
但是,当我运行第一个命令时,hostname = 'test-node-1'
function = 'nodelist'
os.system(f"ssh -i ~/.ssh/my-ssh-key username@serverlocation \"sed -i '/{hostname}/s/$/ 0/' ~/{function}.txt\"")
结果变成了这样,test-node-1 0
test-node-2
...
test-node-11 0
test-node-12 0
test-node-13 0
...
test-node-21
我尝试像这样在命令中添加一个\b,os.system(f"ssh -i ~/.ssh/my-ssh-key username@serverlocation \"sed -i '/\b{hostname}\b/s/$/ 0/' ~/{function}.txt\"")
该命令根本不起作用。我必须手动输入节点名称,而不是像这样使用变量,
os.system(f"ssh -i ~/.ssh/my-ssh-key username@serverlocation \"sed -i '/\btest-node-1\b/s/$/ 0/' ~/{function}.txt\"")
使我的命令起作用。我的命令有什么问题,为什么我不能做我想让它做的事情?
最佳答案
此代码存在严重的安全问题;修复它们需要从头开始重新设计。让我们在这里这样做:
#!/usr/bin/env python3
import os.path
import shlex # note, quote is only here in Python 3.x; in 2.x it was in the pipes module
import subprocess
import sys
# can set these from a loop if you choose, of course
username = "whoever"
serverlocation = "whereever"
hostname = 'test-node-1'
function = 'somename'
desired_cmd = ['sed', '-i',
f'/\\b{hostname}\\b/s/$/ 0/',
f'{function}.txt']
desired_cmd_str = ' '.join(shlex.quote(word) for word in desired_cmd)
print(f"Remote command: {desired_cmd_str}", file=sys.stderr)
# could just pass the below direct to subprocess.run, but let's log what we're doing:
ssh_cmd = ['ssh', '-i', os.path.expanduser('~/.ssh/my-ssh-key'),
f"{username}@{serverlocation}", desired_cmd_str]
ssh_cmd_str = ' '.join(shlex.quote(word) for word in ssh_cmd)
print(f"Local command: {ssh_cmd_str}", file=sys.stderr) # log equivalent shell command
subprocess.run(ssh_cmd) # but locally, run without a shell
如果您运行此程序(最后的 subprocess.run
除外,这需要真正的 SSH key 、主机名等),输出如下所示:Remote command: sed -i '/\btest-node-1\b/s/$/ 0/' somename.txt
Local command: ssh -i /home/yourname/.ssh/my-ssh-key whoever@whereever 'sed -i '"'"'/\btest-node-1\b/s/$/ 0/'"'"' somename.txt'
这是正确/期望的输出;有趣的'"'"'
idiom 是在符合 POSIX 的 shell 中安全地将文字单引号注入(inject)到单引号字符串中的方式。有什么不同?很多:
~
到远程服务器:这是多余且不必要的,因为 ~
是 SSH session 开始的默认位置;并且我们使用的安全预防措施(防止值被 shell 解析为代码)防止它产生任何影响(因为 ~
的事件值替换 HOME
不是由 sed
完成的。本身,而是通过调用它的 shell;因为我们根本没有调用任何本地 shell,所以我们还需要使用 os.path.expanduser
来使 ~
中的 ~/.ssh/my-ssh-key
得到尊重)。 \b
中的反斜杠加倍。以确保它们被 Python 视为文字而不是语法。 关于python - 在带有 os.system 的 python 脚本中正确使用 ssh 和 sed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63865912/