swift - Running A Shell Script With Swift in Cocoa
问题描述
I'm working on a Mac desktop app and trying to run a shell script. I'm getting hung up on setting a launch path for the task. Here's the code:
let path = fileURL.deletingLastPathComponent().relativePath
//set new filename
let strNewFileName = fileURL.deletingPathExtension().lastPathComponent.appending(".html")
let newPath = path + "/" + strNewFileName
//create script
var strScript = "pandoc -s -o "
strScript.append(newPath)
strScript.append(" ")
strScript.append(fileURL.absoluteString)
//set storage path
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
var documentPath:URL = URL(string: documentsPath)!
documentPath.appendPathComponent("pandoc.sh")
var myURLComponents = URLComponents()
myURLComponents.scheme = "file"
myURLComponents.path = documentPath.absoluteString
do {
//write file
try strScript.write(to: myURLComponents.url!, atomically: true, encoding: String.Encoding.utf8)
//run script
let myTask = Process()
myTask.launchPath = "/usr/bin/env"
myTask.arguments = [strScript]
let myPipe = Pipe()
myTask.standardOutput = myPipe
myTask.launch()
let data = myPipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
print(output!)
} catch {
print(error.localizedDescription)
}
This throws a no such file error:
env: pandoc -s -o /Users/stevensuranie/Desktop/MarkdownFiles/targeting-params-ios.html file:///Users/stevensuranie/Desktop/MarkdownFiles/targeting-params-ios.md: No such file or directory
Any help would be appreciated.
解决方案
This line cannot work
var documentPath:URL = URL(string: documentsPath)!
URL(string
is for URL strings including the scheme (file://
or https://
), for file system paths you must use URL(fileURLWithPath
.
However if you use the URL related API of FileManager
you can avoid the init
method at all.
A similar issue is absoluteString
, never call it on a file system URL, use always path
.
A second fatal issue is that each shell argument must be an item in the arguments
array and the executable must be specified with the full path
//create script
let scriptArguments = ["/path/to/pandoc", "-s", "-o", newPath, fileURL.path]
//set storage path
let documentsURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let scriptURL = documentsURL.appendingPathComponent("pandoc.sh")
The following lines are redundant
var myURLComponents = URLComponents()
myURLComponents.scheme = "file"
myURLComponents.path = documentPath.absoluteString
The write the string to scriptURL
do {
//write file
try strScript.write(to: scriptURL, atomically: true, encoding: .utf8)
...
myTask.arguments = scriptArguments
And finally don't use NS...
classes in Swift
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
Use the native
equivalent
let output = String(data: data, encoding: .utf8)
推荐阅读
- python - 如何使用在它之外的for循环中定义的变量?
- angular - 未安装我的库的依赖包(@angular/material/core not found)
- ssh - 如何使用受密码保护的私有 ssh 密钥连接 MySQL Workbench?
- java - JPanel 中的菜单
- linux - 增加 docker ram 在 linux 上安装哨兵服务器
- python - 在 PHP 变量中获取 Python 脚本输出
- reactjs - *.d.ts 在新机器上安装 npm 后的不同类型定义
- android - 将nestedscrollview滚动到textView的底部
- laravel - Laravel 8:尝试通过 JSON Get Testing 测试控制器方法,但找不到路由
- swift - Swift - 创建高频正弦波