我正在尝试通过 SSH 执行命令,但另一端的 bash 认为它没有正确转义。
这里,self._client是一个paramiko.SSHClient对象; args 是一个参数列表,即要执行的命令。
def run(self, args, stdin=None, capture_stdout=False):
"""Runs a command.
On success, returns the output, if requested, or None.
On failure, raises CommandError, with stderr and, if captured, stdout,
as well as the exit code.
"""
command = ' '.join(_shell_escape(arg) for arg in args)
print('About to run command:\n {}'.format(command))
print('About to run command:\n {!r}'.format(command))
channel = self._client.get_transport().open_session()
channel.exec_command(command)
_shell_escape:
_SHELL_SAFE = _re.compile(r'^[-A-Za-z0-9_./]+$')
def _shell_escape(s):
if _SHELL_SAFE.match(s):
return s
return '\'{}\''.format(s.replace('\'', '\'\\\'\''))
我试图通过它运行一些 Python。在 stderr 上,我返回:
bash: -c: line 5: unexpected EOF while looking for matching `''
bash: -c: line 6: syntax error: unexpected end of file
两个打印语句的输出:
About to run command:
python -c 'import os, sys
path = sys.argv[1]
if sys.version_info.major == 2:
path = path.decode('\''utf-8'\'')
entries = os.listdir(path)
out = b'\'''\''.join(e.encode('\''utf-8'\'') + b'\'''\'' for e in entries)
sys.stdout.write(out)
' .
About to run command:
"python -c 'import os, sys\npath = sys.argv[1]\nif sys.version_info.major == 2:\n path = path.decode('\\''utf-8'\\'')\nentries = os.listdir(path)\nout = b'\\'''\\''.join(e.encode('\\''utf-8'\\'') + b'\\''\x00'\\'' for e in entries)\nsys.stdout.write(out)\n' ."
如果我复制并粘贴 command 的输出,并将其粘贴到 bash 中,它就会执行,所以它确实看起来确实被正确转义了。我目前的理解是,在另一端,SSH 将接受命令并运行 [my_shell, '-c', command]。
为什么 bash 在该命令上出错?
请您参考如下方法:
输入包含一个嵌入的 nul 字符,bash 似乎将其视为字符串的结尾。 (我不确定有什么办法不能!)。这在我的问题中可见,我在其中输出 command:
About to run command:
"python -c 'import os, sys [SNIP…] + b'\\''\x00'\\'' for [SNIP…]"
这是一个 repr 输出,但请注意 \x00 中 x 之前的单斜杠:这是一个实际的 \x00 让它通过了。我的原始代码将这个 Python 作为片段嵌入,但我没有包含它(我认为它不相关):
_LS_CODE = """\
import os, sys
path = sys.argv[1]
if sys.version_info.major == 2:
path = path.decode('utf-8')
entries = os.listdir(path)
out = b''.join(e.encode('utf-8') + b'\x00' for e in entries)
sys.stdout.write(out)
"""
在这里,Python 的 """ 仍在处理 \ 作为转义字符。我需要加倍,或查看原始字符串 (r""")
