从GoogleDrive文件夹移动文件手动可行但自动执行失败求助
Crontab执行Google Drive文件移动脚本时出现资源死锁错误
脚本代码
def move_files(source_dirs, dest_dirs, file_patterns): """Move files from source directories to destination directories based on patterns.""" if any("GoogleDrive" in dir for dir in source_dirs + dest_dirs): pause_sync_gdrive() filepaths = [] # List of new paths (destination paths) original_destinations = [] # List of original paths dest_dir_cycle = itertools.cycle(dest_dirs) # Iterator that cycles through dest_dirs for source_dir in source_dirs: for pattern in file_patterns: for filename in glob.glob(os.path.join(source_dir, pattern)): try: # Get the next destination directory from the cycle dest_dir = next(dest_dir_cycle) dest_path = os.path.join(dest_dir, os.path.basename(filename)) os.rename(filename, dest_path) filepaths.append(dest_path) original_destinations.append(filename) except OSError as e: logging.error(f"Failed to move file from {filename} to {dest_path}: {e}") log_environment() # Log environmental variables at the start investigate_file_lock(filename) # Investigate the file lock if any("GoogleDrive" in dir for dir in source_dirs + dest_dirs): resume_sync_gdrive() return filepaths, original_destinations
问题现象
手动运行脚本时一切正常,但通过crontab定时执行时,持续出现资源死锁错误:
Failed to move file from /Users/machine/Library/CloudStorage/GoogleDrive-Account1@gmail.com/My Drive/AUTOProc/testfile.pdf to /Users/machine/UTILS/ToProcess/testfile.pdf: [Errno 11] Resource deadlock avoided: '/Users/machine/Library/CloudStorage/GoogleDrive-Account1@gmail.com/My Drive/AUTOProc/testfile.pdf' -> '/Users/machine/UTILS/ToProcess/testfile.pdf'
已排查信息
- 系统电源设置:
Settings: System-wide power settings: Currently in use: standby 0 Sleep On Power Button 1 autorestart 0 SleepServices 0 powernap 0 networkoversleep 0 disksleep 10 sleep 0 (sleep prevented by powerd) ttyskeepawake 1 displaysleep 0 tcpkeepalive 1 womp 0
- 文件锁排查(lsof命令):
No lsof output for /Users/machine/Library/CloudStorage/GoogleDrive-Account1@gmail.com/My Drive/AUTOProc/testfile.pdf. File might not be locked.
可能原因及解决方案
1. Google Drive同步暂停未生效(crontab环境差异)
手动运行时用户环境变量完整,pause_sync_gdrive能正常调用GDrive的同步暂停命令;但crontab运行在系统级会话,缺失PATH或GDrive相关环境变量,导致暂停命令未实际执行,后台同步线程仍在读写文件,引发死锁。
解决:
- 在crontab的脚本开头显式设置环境变量,例如:
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin,或者将pause_sync_gdrive中用到的命令替换为绝对路径。 - 暂停同步后添加2-3秒延迟(
time.sleep(2)),确保GDrive同步彻底停止后再操作文件。
2. Google Drive虚拟文件系统未就绪
crontab在后台执行时,可能GDrive的云端文件还未完成本地同步或虚拟文件系统未完全挂载,此时glob.glob找到的文件仅为缓存占位符,实际文件不可用,移动操作触发死锁。
解决:
- 脚本开头添加GDrive目录可用性检查:比如尝试读取目录下的一个测试文件,或用
os.stat验证文件状态,确认就绪后再继续。 - 对每个找到的文件,先执行简单的读写测试(
with open(filename, 'rb') as f: f.read(1)),确保文件可正常访问后再移动。
3. 跨文件系统移动的锁机制冲突
os.rename在跨文件系统(GDrive虚拟FS到本地FS)时,依赖内核的原子操作,但GDrive的虚拟FS可能存在特殊的锁机制,crontab的系统级进程权限无法绕过,导致死锁。
解决:
- 改用
shutil.move替代os.rename,shutil.move在跨文件系统时会先复制文件到目标目录,再删除原文件,避免直接rename的锁冲突。 - 确保crontab运行的用户与手动执行脚本的用户完全一致,避免权限差异导致的文件访问限制。
4. 脚本执行时机的竞争问题
crontab执行时可能恰逢系统负载较高,或GDrive正在进行后台元数据更新,此时文件移动操作与GDrive同步线程产生资源竞争,触发内核的死锁规避机制。
解决:
- 给每个文件移动操作添加短暂延迟(
time.sleep(0.5)),降低操作频率,减少竞争概率。 - 移动前检查目标路径是否存在,若存在则临时重命名目标文件或跳过当前文件,避免冲突。
内容的提问来源于stack exchange,提问作者MrT77
相关产品推荐
相关产品推荐

