为何pysftp库中chdir对execute无作用?跨平台脚本执行疑问
Hey there! Let's break down your questions one by one—this stuff can be tricky, but I’ve been there too.
This usually boils down to system PATH environment variables, file permissions, and differences in execution methods. Let’s split it by Unix and Windows scenarios:
Unix System Common Causes
- Script directory not in PATH: When you type a script name directly (like
my_script.py), the system searches all directories listed in yourPATHvariable. If/home/alex_testisn’t inPATH, the system can’t find it. Using an absolute path (/home/alex_test/my_script.py) or running./my_script.pyafter cd-ing into the directory works because you’re explicitly telling the system where the file is, bypassing the PATH lookup. - Missing executable permissions: Even if the directory is in PATH, if the script doesn’t have execute permissions (the
xflag), typing the script name directly will fail. Fix this withchmod +x /home/alex_test/my_script.py, and add a shebang line at the top of the script (like#!/usr/bin/env python3) so the system knows to use Python to run it. Alternatively, runningpython3 /home/alex_test/my_script.pyworks because you’re directly calling Python to process the file, no executable permission required.
Windows System Common Causes
- Script directory not in PATH: Same logic as Unix—if the script’s folder (e.g.,
C:\Users\alex_test) isn’t in Windows’PATH, typing the script name directly will throw a "not found" error. Using the absolute path or cd-ing into the directory first then runningmy_script.pyfixes this. - Python association issue: If Windows hasn’t associated
.pyfiles with the Python interpreter, double-clicking or typing the script name might pop up an "open with" dialog instead of running it. Usepy -3 my_script.py(with the Python Launcher) orpython my_script.pyin the command line to get around this.
I’ve stumbled on this exact pitfall before! The core reason is: pysftp’s chdir() modifies the local SFTP client’s current working directory, while execute() runs commands in a brand new shell session on the remote server—these two operations are completely independent and don’t inherit each other’s state.
Example of the behavior:
import pysftp with pysftp.Connection('remote_host', username='user', password='pass') as sftp: sftp.chdir('/remote/workdir') # Changes the client's local working directory result = sftp.execute('pwd') # Runs pwd in a fresh remote shell print(result) # Outputs the remote user's default directory (e.g., /home/user), NOT /remote/workdir
Every time you call execute(), the remote server spins up a new shell process, which starts in the remote user’s default login directory—it doesn’t care about the path you set via the SFTP client’s chdir().
Fixes
Two reliable ways to make execute() run commands in your target directory:
- Explicitly change directory in the command chain: Use
cdplus&&to ensure the directory switch happens before your command runs:sftp.execute('cd /remote/workdir && ls -l') - Use absolute paths for commands/files: If you’re running a script or program, specify its full path directly instead of switching directories:
sftp.execute('/remote/workdir/my_remote_script.sh')
To make your code work seamlessly across both systems, focus on path handling and execution logic adaptation:
- Use
pathlibfor paths: Python 3.4+’spathlibauto-adapts to system-specific path separators (/for Unix,\for Windows) so you don’t have to hardcode them:from pathlib import Path script_dir = Path('/home/alex_test') # Automatically becomes C:\home\alex_test on Windows script_path = script_dir / 'my_script.py' - Call Python with
sys.executable: Unix usespython3, Windows usespythonorpy—sys.executablegrabs the current environment’s Python interpreter path to avoid mismatches:import sys import subprocess subprocess.run([sys.executable, str(script_path)], check=True) - Pysftp cross-platform notes: Remote paths need to match the remote server’s OS. For Windows remotes, use
\\(escaped as\\\\) or/(many SFTP servers support this); for Unix remotes, use/. You can detect the remote OS to adjust dynamically:with pysftp.Connection(...) as sftp: try: remote_os = sftp.execute('uname -s') remote_workdir = '/remote/unix/path' if b'Linux' in remote_os else 'C:\\remote\\windows\\path' except: # Fallback for Windows servers that don't support uname remote_workdir = 'C:\\remote\\windows\\path'
内容的提问来源于stack exchange,提问作者user9343376

