我写了一个小脚本,它可以快速显示一个窗口。目标是显示几个 shell 命令的输出(brew update & brew upgrade & brew cleanup & brew doctor)。如果您不是每天都执行这些命令,那么这些命令可能会花费大量时间,而且我已经厌倦了必须等待 10 分钟才能完成前 2 个命令。
我本可以简单地启动一个 cron 作业或使用带有 shell 脚本的 launchd,但我希望能够检查命令的成功或失败,尤其是 brew doctor,以了解我是否需要执行某些操作清理我的机器上安装的自制软件。
所以我需要一个窗口来显示命令的错误和标准输出等等,我想生成它的二进制文件。
在 Google 和 Github 上搜索了一下,我找到了 swift-sh,它允许导入 Github 存储库(通过 Swift 包管理器以标准化的方式)并在 swift 脚本中使用它并在需要时编译它;和 ShellOut,由同一个人开发,它允许从 swift 脚本执行 shell 命令,并将命令的输出收集到 swift 对象中。
基本上,它应该是一个滚动视图中带有文本视图的小窗口,它显示了 shell 命令的输出,同时能够滚动它。
这里是脚本:
#!/usr/bin/swift sh
import AppKit
import Foundation
// importing ShellOut from GitHub repository
// The magic of swift-sh happens
import ShellOut // @JohnSundell
// Declare the Application context
let app = NSApplication.shared
// Create the delegate class responsible for the window and crontrol creation
class AppDelegate: NSObject, NSApplicationDelegate {
var str: String? = ""
// Construct the window
let theWindow = NSWindow(contentRect: NSMakeRect(200, 200, 400, 200),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered,
defer: false,
screen: nil)
var output: String? = ""
// What happens once application context launched
func applicationDidFinishLaunching(_ notification: Notification) {
var str = ""
// The shell commands and the collect of output
do {
str = try shellOut(to: "brew", arguments: ["update"] )
output = output! + str
} catch {
let error1 = error as! ShellOutError
//print(error1.message)
output = output! + error1.message
}
do {
str = try shellOut(to: "brew", arguments: ["upgrade"] )
output = output! + "\n" + str
//print("step 2")
} catch {
let error2 = error as! ShellOutError
//print(error2.message)
output = output! + "\n" + error2.message
}
do {
str = try shellOut(to: "brew", arguments: ["cleanup"] )
output = output! + "\n" + str
//print("step 3")
} catch {
let error3 = error as! ShellOutError
//print(error3.message)
output = output! + "\n" + error3.message
}
do {
str = try shellOut(to: "brew", arguments: ["doctor"] )
output = output! + "\n" + str
//print("step 4")
} catch {
let error4 = error as! ShellOutError
//print(error4.message)
output = output! + "\n" + error4.message
}
// Controls placement and content goes here
// ScrollView...
var theScrollview = NSScrollView(frame: theWindow.contentView!.bounds)
var contentSize = theScrollview.contentSize
theScrollview.borderType = .noBorder
theScrollview.hasVerticalScroller = true
theScrollview.hasHorizontalScroller = false
theScrollview.autoresizingMask = NSView.AutoresizingMask(rawValue: NSView.AutoresizingMask.width.rawValue | NSView.AutoresizingMask.height.rawValue | NSView.AutoresizingMask.minYMargin.rawValue | NSView.AutoresizingMask.minYMargin.rawValue)
// TextView...
var theTextView = NSTextView(frame: NSMakeRect(0, 0, contentSize.width, contentSize.height))
theTextView.minSize = NSMakeSize(0.0, contentSize.height)
theTextView.maxSize = NSMakeSize(CGFloat.greatestFiniteMagnitude, CGFloat.greatestFiniteMagnitude)
theTextView.isVerticallyResizable = true
theTextView.isHorizontallyResizable = false
theTextView.autoresizingMask = NSView.AutoresizingMask(rawValue: NSView.AutoresizingMask.width.rawValue | NSView.AutoresizingMask.height.rawValue | NSView.AutoresizingMask.minYMargin.rawValue | NSView.AutoresizingMask.minYMargin.rawValue)
theTextView.textContainer?.containerSize = NSMakeSize(contentSize.width, CGFloat.greatestFiniteMagnitude)
theTextView.backgroundColor = .white
theTextView.textContainer?.widthTracksTextView = true
theTextView.textStorage?.append(NSAttributedString(string: output!))
theScrollview.documentView = theTextView
theWindow.contentView = theScrollview
theWindow.makeKeyAndOrderFront(nil)
theWindow.makeFirstResponder(theTextView)
}
// What happens when we click the close button of the window
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true;
}
}
// Instantiation of the application delegate class
// and launching
let delegate = AppDelegate()
app.delegate = delegate
app.run()