在 Swift 5 中正确执行 shell 命令
Correctly execute shell commands in Swift 5
我是 swift 的新手,并尝试按照互联网上的几个不同教程制作我的应用 运行 终端内容。
我有一个复选框,应该启用(通过终端命令)充电提示音(当然,当未选中时将其关闭)。
编辑:
更新的代码,仍然无法正常工作:
@discardableResult func shell(_ command: String) -> String {
let task = Process()
task.launchPath = "/usr/bin/"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
return output
}
@IBAction func SoundBox(_ sender: NSButton) {
if(SoundBox.state == NSControl.StateValue.on){
self.helloLabel.stringValue = "It's On!"
shell("say hello")
//shell("defaults write com.apple.PowerChime ChimeOnAllHardware -bool true; open /System/Library/CoreServices/PowerChime.app &")
}
else if(SoundBox.state == NSControl.StateValue.off){
self.helloLabel.stringValue = "It's off!"
shell("say hello")
//shell("defaults write com.apple.PowerChime ChimeOnAllHardware -bool false; killall PowerChime")
}
新控制台输出:
2019-04-12 16:44:54.792282+0200 TerminApp[2985:45592] [General] Couldn't posix_spawn: error 13
2019-04-12 16:44:54.795254+0200 TerminApp[2985:45592] [General] (
0 CoreFoundation 0x00007fff42444e45 __exceptionPreprocess + 256
1 libobjc.A.dylib 0x00007fff6d07c3c6 objc_exception_throw + 48
2 CoreFoundation 0x00007fff42444c77 +[NSException raise:format:] + 193
3 Foundation 0x00007fff446495e9 -[NSConcreteTask launchWithDictionary:error:] + 4437
4 TerminApp 0x000000010000299b $s9TerminApp14ViewControllerC5shellyS2SF + 635
5 TerminApp 0x000000010000349e $s9TerminApp14ViewControllerC8SoundBoxyySo8NSButtonCF + 1438
6 TerminApp 0x000000010000360c $s9TerminApp14ViewControllerC8SoundBoxyySo8NSButtonCFTo + 60
7 AppKit 0x00007fff3fcf8e80 -[NSApplication(NSResponder) sendAction:to:from:] + 312
8 AppKit 0x00007fff3fd63196 -[NSControl sendAction:to:] + 86
9 AppKit 0x00007fff3fd630c8 __26-[NSCell _sendActionFrom:]_block_invoke + 136
10 AppKit 0x00007fff3fd62fca -[NSCell _sendActionFrom:] + 178
11 AppKit 0x00007fff3fd8fd4f -[NSButtonCell _sendActionFrom:] + 96
12 AppKit 0x00007fff3fd618e5 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2375
13 AppKit 0x00007fff3fd8faa0 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 698
14 AppKit 0x00007fff3fd60322 -[NSControl mouseDown:] + 791
15 AppKit 0x00007fff3fc3c16f -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 5724
16 AppKit 0x00007fff3fb729de -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2295
17 AppKit 0x00007fff3fb71e9f -[NSWindow(NSEventRouting) sendEvent:] + 478
18 AppKit 0x00007fff3fa116c3 -[NSApplication(NSEvent) sendEvent:] + 331
19 AppKit 0x00007fff3f9ffee8 -[NSApplication run] + 755
20 AppKit 0x00007fff3f9ef3f0 NSApplicationMain + 777
21 TerminApp 0x000000010000475d main + 13
22 libdyld.dylib 0x00007fff6e8a13d5 start + 1
)
这就是我在我的应用程序中启动 ffmpeg 的方式。 (ffmpegTask
是一个 Process!
实例,声明为实例 属性,而 prefs.input_uri
是一个字符串,来自用户输入 - 它是 RTSP 流的 URI)。希望这会有所帮助("TemporaryFile" 的内容来自 Ole Begemann's excellent utility):
/* ################################################################## */
/**
This starts the ffmpeg task.
- returns: True, if the task launched successfully.
*/
func startFFMpeg() -> Bool {
ffmpegTask = Process()
// First, we make sure that we got a Process. It's a conditional init.
if let ffmpegTask = ffmpegTask {
// Next, set up a tempdir for the stream files.
if let tmp = try? TemporaryFile(creatingTempDirectoryForFilename: "stream.m3u8") {
outputTmpFile = tmp
// Fetch the executable path from the bundle. We have our copy of ffmpeg in there with the app.
if var executablePath = (Bundle.main.executablePath as NSString?)?.deletingLastPathComponent {
executablePath += "/ffmpeg"
ffmpegTask.launchPath = executablePath
ffmpegTask.arguments = [
"-i", prefs.input_uri,
"-sc_threshold", "0",
"-f", "hls",
"-hls_flags", "delete_segments",
"-hls_time", "4",
outputTmpFile?.fileURL.path ?? ""
]
#if DEBUG
if let args = ffmpegTask.arguments, 1 < args.count {
let path = ([executablePath] + args).joined(separator: " ")
print("\n----\n\(String(describing: path))")
}
#endif
// Launch the task
ffmpegTask.launch()
#if DEBUG
print("\n----\n")
#endif
return ffmpegTask.isRunning
}
}
}
return false
}
沙盒可能是一个问题,具体取决于您调用的位置。 ffmpeg 无论如何都不喜欢沙箱,但我仍然将我为我的应用程序构建的变体嵌入到与主应用程序可执行文件相同的目录中。
我是 swift 的新手,并尝试按照互联网上的几个不同教程制作我的应用 运行 终端内容。
我有一个复选框,应该启用(通过终端命令)充电提示音(当然,当未选中时将其关闭)。
编辑: 更新的代码,仍然无法正常工作:
@discardableResult func shell(_ command: String) -> String {
let task = Process()
task.launchPath = "/usr/bin/"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
return output
}
@IBAction func SoundBox(_ sender: NSButton) {
if(SoundBox.state == NSControl.StateValue.on){
self.helloLabel.stringValue = "It's On!"
shell("say hello")
//shell("defaults write com.apple.PowerChime ChimeOnAllHardware -bool true; open /System/Library/CoreServices/PowerChime.app &")
}
else if(SoundBox.state == NSControl.StateValue.off){
self.helloLabel.stringValue = "It's off!"
shell("say hello")
//shell("defaults write com.apple.PowerChime ChimeOnAllHardware -bool false; killall PowerChime")
}
新控制台输出:
2019-04-12 16:44:54.792282+0200 TerminApp[2985:45592] [General] Couldn't posix_spawn: error 13
2019-04-12 16:44:54.795254+0200 TerminApp[2985:45592] [General] (
0 CoreFoundation 0x00007fff42444e45 __exceptionPreprocess + 256
1 libobjc.A.dylib 0x00007fff6d07c3c6 objc_exception_throw + 48
2 CoreFoundation 0x00007fff42444c77 +[NSException raise:format:] + 193
3 Foundation 0x00007fff446495e9 -[NSConcreteTask launchWithDictionary:error:] + 4437
4 TerminApp 0x000000010000299b $s9TerminApp14ViewControllerC5shellyS2SF + 635
5 TerminApp 0x000000010000349e $s9TerminApp14ViewControllerC8SoundBoxyySo8NSButtonCF + 1438
6 TerminApp 0x000000010000360c $s9TerminApp14ViewControllerC8SoundBoxyySo8NSButtonCFTo + 60
7 AppKit 0x00007fff3fcf8e80 -[NSApplication(NSResponder) sendAction:to:from:] + 312
8 AppKit 0x00007fff3fd63196 -[NSControl sendAction:to:] + 86
9 AppKit 0x00007fff3fd630c8 __26-[NSCell _sendActionFrom:]_block_invoke + 136
10 AppKit 0x00007fff3fd62fca -[NSCell _sendActionFrom:] + 178
11 AppKit 0x00007fff3fd8fd4f -[NSButtonCell _sendActionFrom:] + 96
12 AppKit 0x00007fff3fd618e5 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2375
13 AppKit 0x00007fff3fd8faa0 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 698
14 AppKit 0x00007fff3fd60322 -[NSControl mouseDown:] + 791
15 AppKit 0x00007fff3fc3c16f -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 5724
16 AppKit 0x00007fff3fb729de -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2295
17 AppKit 0x00007fff3fb71e9f -[NSWindow(NSEventRouting) sendEvent:] + 478
18 AppKit 0x00007fff3fa116c3 -[NSApplication(NSEvent) sendEvent:] + 331
19 AppKit 0x00007fff3f9ffee8 -[NSApplication run] + 755
20 AppKit 0x00007fff3f9ef3f0 NSApplicationMain + 777
21 TerminApp 0x000000010000475d main + 13
22 libdyld.dylib 0x00007fff6e8a13d5 start + 1
)
这就是我在我的应用程序中启动 ffmpeg 的方式。 (ffmpegTask
是一个 Process!
实例,声明为实例 属性,而 prefs.input_uri
是一个字符串,来自用户输入 - 它是 RTSP 流的 URI)。希望这会有所帮助("TemporaryFile" 的内容来自 Ole Begemann's excellent utility):
/* ################################################################## */
/**
This starts the ffmpeg task.
- returns: True, if the task launched successfully.
*/
func startFFMpeg() -> Bool {
ffmpegTask = Process()
// First, we make sure that we got a Process. It's a conditional init.
if let ffmpegTask = ffmpegTask {
// Next, set up a tempdir for the stream files.
if let tmp = try? TemporaryFile(creatingTempDirectoryForFilename: "stream.m3u8") {
outputTmpFile = tmp
// Fetch the executable path from the bundle. We have our copy of ffmpeg in there with the app.
if var executablePath = (Bundle.main.executablePath as NSString?)?.deletingLastPathComponent {
executablePath += "/ffmpeg"
ffmpegTask.launchPath = executablePath
ffmpegTask.arguments = [
"-i", prefs.input_uri,
"-sc_threshold", "0",
"-f", "hls",
"-hls_flags", "delete_segments",
"-hls_time", "4",
outputTmpFile?.fileURL.path ?? ""
]
#if DEBUG
if let args = ffmpegTask.arguments, 1 < args.count {
let path = ([executablePath] + args).joined(separator: " ")
print("\n----\n\(String(describing: path))")
}
#endif
// Launch the task
ffmpegTask.launch()
#if DEBUG
print("\n----\n")
#endif
return ffmpegTask.isRunning
}
}
}
return false
}
沙盒可能是一个问题,具体取决于您调用的位置。 ffmpeg 无论如何都不喜欢沙箱,但我仍然将我为我的应用程序构建的变体嵌入到与主应用程序可执行文件相同的目录中。