NSAppleScript脚本字符串插值引发磁盘挂载无效问题求助
AppleScript引入变量后挂载磁盘失败问题解决
问题场景
静态写死磁盘名的AppleScript脚本通过NSAppleScript执行完全正常:
do shell script "mount -o nobrowse -t apfs /dev/disk3s1 ~/Unscrewer" user name "lucasdrouot" password "MDP" with administrator privileges
但将磁盘名替换为Swift变量(哪怕是静态赋值的mainDiskName)后,脚本返回「磁盘无效」错误,相关Swift代码如下:
@State var mainDiskName: String = "disk3s1" func mountSystemVolume() { runCommand("mkdir -p ~/Unscrewer") let fileManager = FileManager.default let homeDirectory = fileManager.homeDirectoryForCurrentUser let folderPath = homeDirectory.appendingPathComponent("Unscrewer") if fileManager.fileExists(atPath: folderPath.path, isDirectory: nil) { let diskName = mainDiskName appleScript(""" do shell script "mount -o nobrowse -t apfs /dev/\(diskName) ~/Unscrewer" user name "lucasdrouot" password "MDP" with administrator privileges """) } else { errorAlert = true alertTitle = "No such file or directory" let errorDetails = """ More Info: No such file or directory: ~/Unscrewer """ alertMessage = errorDetails } }
问题原因
直接在AppleScript字符串中进行Swift插值,会导致生成的脚本存在语法隐患:
- AppleScript对字符串的解析逻辑与Swift不同,插值后的命令字符串可能因换行、缩进或未转义的字符被错误解析
do shell script中的变量未经过quoted form of处理,若变量包含特殊字符(哪怕当前是纯字母数字),也会触发shell命令执行异常
解决方案
方案1:修正AppleScript变量传递方式
通过AppleScript自身的变量处理逻辑传递参数,避免Swift插值的语法冲突,同时用quoted form of确保shell命令的安全性:
@State var mainDiskName: String = "disk3s1" func mountSystemVolume() { runCommand("mkdir -p ~/Unscrewer") let fileManager = FileManager.default let homeDirectory = fileManager.homeDirectoryForCurrentUser let folderPath = homeDirectory.appendingPathComponent("Unscrewer") if fileManager.fileExists(atPath: folderPath.path, isDirectory: nil) { let diskName = mainDiskName let scriptString = """ set diskDevice to "/dev/\(diskName)" set mountPoint to (path to home folder as text) & "Unscrewer" do shell script "mount -o nobrowse -t apfs " & quoted form of diskDevice & " " & quoted form of POSIX path of mountPoint user name "lucasdrouot" password "MDP" with administrator privileges """ appleScript(scriptString) } else { errorAlert = true alertTitle = "No such file or directory" alertMessage = "More Info: No such file or directory: ~/Unscrewer" } }
方案2:直接用Swift执行Shell命令(更推荐)
Swift应用无需依赖AppleScript,直接通过Process执行sudo mount命令,更可控且避免AppleScript的语法陷阱:
@State var mainDiskName: String = "disk3s1" @State var errorAlert = false @State var alertTitle = "" @State var alertMessage = "" func mountSystemVolume() { let mountPoint = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Unscrewer") // 确保挂载目录存在 try? FileManager.default.createDirectory(at: mountPoint, withIntermediateDirectories: true) let diskPath = "/dev/\(mainDiskName)" let task = Process() let pipe = Pipe() task.standardOutput = pipe task.standardError = pipe task.executableURL = URL(fileURLWithPath: "/usr/bin/sudo") // sudo参数:-S从标准输入读取密码,后续为mount命令参数 task.arguments = ["-S", "mount", "-o", "nobrowse", "-t", "apfs", diskPath, mountPoint.path] // 传递sudo密码(注意:硬编码密码存在安全风险,建议改用系统权限弹窗) let passwordData = "MDP\n".data(using: .utf8)! task.standardInput = Pipe() (task.standardInput as! Pipe).fileHandleForWriting.write(passwordData) (task.standardInput as! Pipe).fileHandleForWriting.closeFile() do { try task.run() task.waitUntilExit() let outputData = pipe.fileHandleForReading.readDataToEndOfFile() let outputString = String(data: outputData, encoding: .utf8) if task.terminationStatus != 0 { errorAlert = true alertTitle = "挂载失败" alertMessage = outputString ?? "磁盘无效或权限错误" } } catch { errorAlert = true alertTitle = "执行错误" alertMessage = error.localizedDescription } }
注意:硬编码密码存在严重安全风险,生产环境建议改用
AuthorizationServices框架申请管理员权限,避免明文存储密码。
内容的提问来源于stack exchange,提问作者ldt
相关产品推荐
相关产品推荐

