如何避免sudo执行Swift文件回收代码时文件进入root回收站?
解决sudo执行时文件移入root回收站的问题
好问题!要避免sudo运行脚本时文件被移入root的回收站,同时又不硬编码用户回收站路径、也不提前降低权限,核心思路是在执行回收站操作前,临时切换回调用sudo的原用户身份——毕竟macOS的trashItemAPI会自动对应当前用户的回收站,只要身份是原用户,就会正确放入对应的位置。
下面是修改后的脚本,关键是利用sudo环境下的SUDO_UID和SUDO_GID环境变量来切换身份:
#!/usr/bin/swift import Darwin struct swifterr: TextOutputStream { public static var stream = swifterr() mutating func write(_ string: String) { fputs(string, stderr) } } // 处理sudo下的身份切换 if let sudoUidStr = ProcessInfo.processInfo.environment["SUDO_UID"], let sudoGidStr = ProcessInfo.processInfo.environment["SUDO_GID"], let sudoUid = uid_t(sudoUidStr), let sudoGid = gid_t(sudoGidStr) { // 先切换组ID,再切换用户ID(posix要求的顺序) if posix_setgid(sudoGid) != 0 { print("Failed to switch to original group ID: \(strerror(errno))", to: &swifterr.stream) exit(1) } if posix_setuid(sudoUid) != 0 { print("Failed to switch to original user ID: \(strerror(errno))", to: &swifterr.stream) exit(1) } } if CommandLine.arguments.count < 2 { print("Usage: \(CommandLine.arguments[0]) <file1> [file2...]", to: &swifterr.stream) exit(2) } let manager: FileManager = FileManager.default for item in CommandLine.arguments[1...] { do { let path: URL = URL(fileURLWithPath: item) var destination: NSURL? try manager.trashItem(at: path, resultingItemURL: &destination) } catch { print("Failed to trash \(item): \(error.localizedDescription)", to: &swifterr.stream) exit(1) } } exit(0)
关键说明:
- 身份切换逻辑:当脚本通过sudo运行时,系统会自动设置
SUDO_UID和SUDO_GID环境变量,分别对应调用sudo的原用户的UID和GID。我们通过这两个值切换回原用户身份,再执行trashItem操作。 - 切换顺序:必须先调用
posix_setgid切换组ID,再调用posix_setuid切换用户ID——因为一旦切换到普通用户身份,就可能没有权限修改组ID了。 - 兼容性:这个方法完全依赖系统原生的环境变量和posix接口,不需要硬编码任何路径,也不需要额外依赖工具,符合你的需求。
测试一下:用sudo运行这个脚本删除文件,文件会出现在你自己的回收站里,而不是root的回收站;普通用户直接运行也完全正常。
内容的提问来源于stack exchange,提问作者amyspark
相关产品推荐
相关产品推荐

