使用Python脚本执行Bash的scp传输命令失败,求助排查方案
我之前也踩过类似的坑——手动跑scp顺得不行,一用Python脚本就掉链子,总结下来通常是这几个问题在搞鬼:
路径转义的坑:你在Bash里用的反斜杠
\是Windows路径格式,但Python里反斜杠是转义字符啊!比如\local\path\这种写法,Python会把\l当成无效转义序列报错,或者直接解析出错误的路径。解决办法要么把路径改成正斜杠/,要么用Python的原始字符串(在字符串前加r),比如r"scp /local/path/ user@remoteip:/path/to/copy/onremote"。subprocess调用方式不对:如果用
subprocess模块时,直接把整个命令串当单个参数传,又没加shell=True,Python会把整个字符串当成一个命令去系统里找,自然找不到scp。正确的姿势是把命令拆成列表形式:import subprocess subprocess.run(["scp", "/local/path/", "user@remoteip:/path/to/copy/onremote"])要是非得用字符串形式,记得加上
shell=True,不过这种方式要注意安全,别传用户可控的内容进去。身份验证的交互没处理:手动跑scp的时候,你可能输入过密码,或者ssh-agent帮你托管了密钥,但Python脚本运行时没有交互环境,没法输入密码,也可能没继承你的ssh代理环境。这种情况最好配置无密码的ssh密钥对(把本地公钥传到远程服务器的
~/.ssh/authorized_keys里),或者用paramiko、scp这类专门的Python库,它们能程序化处理密钥或密码认证,比直接调用scp靠谱多了。权限不匹配:脚本运行的用户和你手动执行Bash的用户可能不一样!比如你用自己的账号手动跑没问题,但脚本用root或者其他用户运行,可能没权限读本地文件,或者没权限写远程服务器的目标路径。可以检查下脚本运行的用户身份,或者给对应路径调整权限。
特殊字符没处理好:如果你的本地或远程路径里有空格、引号这类特殊字符,手动在Bash里会用引号包裹,但Python里要是没正确处理,命令就会解析出错。比如路径是
/my docs/file.txt,用列表形式传参数的话,直接写"/my docs/file.txt"就行,subprocess会自动处理;要是用字符串形式,就得手动转义,比如"scp \"/my docs/file.txt\" user@remoteip:/remote/path/",不过还是列表形式更省心。
内容的提问来源于stack exchange,提问作者rawplutonium

