我正在开发一项功能,以启用将由 Mac 应用程序执行的用户提供的脚本。
NSUserScriptTask
是脚本调用代码的基础,NSUserAppleScriptTask
和 NSUserAutomatorTask
子类都允许设置变量以将信息从 Swift 传递到脚本:
Passing variables to an AppleScript
Setting NSUserAutomatorTask variables without requiring Automator Workflows to declare that variable
剩下 NSUserUnixTask
,它不支持设置变量。相反,它支持名为 arguments
的 [String]
数组。
执行脚本时,我想从 Mac 应用程序传递 3 个变量:
let folderURL: String? = "/files/"
let fileURLs: [String] = ["/files/file1", "/files/file2"]
let selectionType: Int? = 1
let arguments: [String] = ["how", "should", "arguments", "be", "formatted", "?"]
let unixScript = try! NSUserUnixTask(url: url)
unixScript.execute(withArguments: arguments) { (error) in
if let error = error {
print(error)
}
}
必须将 3 个 swift 变量压缩到一个 [String]
数组中,以便 NSUserUnixTask
用作其 arguments
参数。
当脚本运行时,我想以原型(prototype)方式为脚本作者提供对相同参数的访问权限:
#! /bin/bash
say "How should the script then access/parse the arguments?"
say $@ #says the arguments
基于脚本作者的易用性,Swift 代码应如何将其信息格式化为参数 [String]
?
可以提供哪些样板代码以允许从脚本中轻松实用地访问参数?
最佳答案
有很多方法可以做到这一点,这取决于 shell 脚本程序员的期望。如果我是他们中的一员,我会要求您保持简单:
- 位置参数(开始时固定数量的强制参数)
- 可选的命名参数(
-flag value
样式的任何参数) - 更多参数(可变数量的附加参数)
按照您的示例,稍作修改:
import Foundation
let shellScript = CommandLine.arguments[1]
let folderURL: String = "/files/"
let fileURLs: [String] = ["/files/file1", "/files/file2"]
let selectionType: Int? = 1
var arguments = [String]()
// script.sh <folder> [-type <type>] file1, file2, ...
arguments.append(folderURL) // <folder> is mandatory
if let type = selectionType { // -type <type> is optional
arguments.append("-type")
arguments.append("\(type)")
}
arguments += fileURLs // file1, ... (if it can't be empty check it here)
assert(FileManager.default.fileExists(atPath: shellScript))
let unixScript = try! NSUserUnixTask(url: URL(fileURLWithPath: shellScript))
let stdout = FileHandle.standardOutput
unixScript.standardOutput = stdout
unixScript.execute(withArguments: arguments) { error in
if let error = error {
print("Failed: ", error)
}
exit(0)
}
dispatchMain() // I'm not swift script expert, there may be a better way
以及对应的shell脚本:
#!/bin/bash
# mandatory positional arguments
FOLDER=$1 && shift
# other mandatory arguments goes here
TYPE=7 # default type
FILES=()
while [[ $# -gt 0 ]]; do
arg=$1
case $arg in
-type)
TYPE=$2 && shift && shift
;;
# other named parameters here
*)
FILES+=($1) && shift
;;
esac
done
echo FOLDER: '<'${FOLDER}'>'
echo TYPE: '<'${TYPE}'>'
echo FILES: '<'${FILES[@]}'>'
exit 0
例子:
ScriptRunner /path/to/script.sh
输出:
FOLDER: </files/>
TYPE: <1>
FILES: </files/file1 /files/file2>
我使用 swift 包管理器构建:
// swift-tools-version:4.2
import PackageDescription
let package = Package(
name: "ScriptRunner",
dependencies: [],
targets: [
.target(name: "ScriptRunner", dependencies: [])
]
)
关于swift - 如何通过 NSUserUnixTask 传递参数,然后通过脚本访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52561768/