我正在开发一项功能,以启用将由Mac应用程序执行的用户提供的脚本。
NSUserScriptTask
是脚本调用代码的基础,而NSUserAppleScriptTask
和NSUserAutomatorTask
子类都允许设置变量以将信息从Swift传递到脚本:
Passing variables to an AppleScript
Setting NSUserAutomatorTask variables without requiring Automator Workflows to declare that variable
剩下NSUserUnixTask
,它不支持设置变量。相反,它支持名为[String]
的{{1}}数组。
执行脚本时,我要从Mac应用程序传递3个变量:
arguments
必须将3个swift变量压缩到单个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)
}
}
数组中,[String]
才能用作其NSUserUnixTask
参数。
当脚本运行时,我想以一种典型的方式为脚本作者提供对相同参数的访问权限:
arguments
基于脚本作者的易用性,Swift代码应如何将其信息格式化为参数#! /bin/bash
say "How should the script then access/parse the arguments?"
say $@ #says the arguments
?
可以提供哪些样板代码来轻松,实用地从脚本访问参数?
答案 0 :(得分:3)
有许多方法可以做到这一点,这取决于程序员对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: [])
]
)