Scripting Swift

作为iOS开发者,从苹果刚推出Swift到现在,断断续续也用了一段时间了。Swift本身语法很简洁很现代,但实际应用在项目中走过的坑还真不少😂,不过好在都有解决办法,而且总体上开发者应该都是很认可这个语言的。在学习和使用swift的过程中,相信大家肯定从这门语言身上都看到了很多现代语言的影子,比如Python、JavaScript等等。不过,除了语法层面可以和这些语言类比,今天我们可以从另一面对比一下它们,就是用来写脚本。对的,其实swift不仅可以用来写 iOS or Mac OS,只要装了Xcode,我们就可以像用Python一样,在Mac下面用Swift来写脚本。

Well… Long story short, Let’s Get Started~~

Hello world

首先,最简单的,我们先来在终端用swift输出hello world试试。
输入 swift into the terminal然后回车,输入任何swift语句比如打印hello world,使用Ctrl-D退出:

1
2
3
4
$ swift
Welcome to Apple Swift. Type :help for assistance.
1> print(“Hello World”)
2>

这就像Python一样,swift命令行的交互模式叫做 Swift REPL (read eval print loop)
既然是按照脚本执行,肯定就存在这对应的解析执行脚本的程序。先看看我们平时用的bash:

1
2
3
4
5
6
7
8
9
10
11
$ cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

这里当然没有了,不过如果我们执行type命令可以看到如下输出:

1
2
$ type swift
swift is hashed (/usr/bin/swift)

注意到/usr/bin/swift了吗,事实上这就是我们要找的了。

在swift脚本文件最上面加上#!/usr/bin/swift (或者 #!/usr/bin/env swift) 就启动swift解释器了, 后面的语句就会在swift环境下面编译。无需多说,这基本和我们以前使用bash时 要加入 #!/bin/bash一样。

接下来我们就创建一个demo.swift,做个最简单的测试:

1
2
$touch demo.swift
$vim demo.swift

编辑demo.swift文件:

1
2
3
4
#!/usr/bin/swift

import Foundation
print("hello world")

编辑保存后,给它可执行的权限后,./demo.swift运行肯定就看到输出效果了。这样就是最简单的swift_脚本了_:

1
2
3
$chmod +x demo.swift
$./demo.swift
hello world

Demo time:

下面简单写一个可以传参数的demo,假设我们要做一个可以一键备份我的博客的功能。其实就是把文章Push到对应的Git服务器。

按照之前的步骤,创建一个新的 backup.swift文件,用来提交我的博客到git服务器,同时需要添加本次提交相应的描述。这样的话,这里我们要解决两个问题。

  1. 既然提交的描述是动态的,需要通过参数传入。我们就能获取到命令行传入的参数。
  2. 需要在swift里面调用其他命令行工具,比如语句: git pull。

要解决第一个问题,我们需要引用一个新的类CommandLine (或者更基础的C_ARGC and C_ARGV也可以)。
CommandLine.arguments是个数组,可以直接通过它拿到想要的参数。
至于第二个问题,我们需要引入另一个在Swift脚本中很重要类 Process。Process很强大,可以混合 swift和bash。这让我们在swift中使用git命令成为可能。

下面就是编写后的backup.swift文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/swift

import Foundation

func backup() {
let args = CommandLine.arguments
guard args.count > 1 else {
return print("Backup Failed! : \n Detail: Missing commit message whick should be surrounded by quotation mark.")
}
let arg = args[1]
shell("git", "pull")
shell("git", "commit", "-am", arg)
shell("git", "push", "origin", "HEAD:source")
}

@discardableResult
func shell(_ args: String...) -> Int32 {
let task = Process()
task.launchPath = "/usr/bin/env"
task.arguments = args
task.launch()
task.waitUntilExit()
return task.terminationStatus
}

backup()

这个例子中,函数 shell(_ args: String...) -> Int32 用来实现Swift调用其他命令行命令。backup() 会先读取输入的参数,然后执行对应的备份操作。
把这个脚本放在我的博客git目录下,运行就会自动开始将内容Push到git服务器了。

1
2
3
4
5
6
7
$ ./backup.swift "Blog: Backup"
remote: Enumerating objects: 139, done.
remote: Counting objects: 100% (139/139), done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 149 (delta 53), reused 139 (delta 53), pack-reused 10
Receiving objects: 100% (149/149), 61.23 KiB | 61.00 KiB/s, done.
...