脚本一般由多个命令和指令构成,可在特定的运行环境中运行。常规的简单程序会选择使用Shell脚本,原因主要是其简洁易读,而对于复杂脚本的编写较为困难。当涉及到第三方库的使用时,Python或Ruby成为编写脚本的首选。Swift3之后也出了解释器,也可以直接通过swift xxx.swift执行简单的swift代码,也可以通过SPM引入第三方库,生成命令行可执行程序的方式封装执行序列。

Shell脚本

  1. 以 #!/bin/sh 开头的文件,程序在执行的时候会调用 /bin/sh ,也就是bash解释器。如果脚本未指定 shebang,脚本执行的时候,默认用当前shell去解释脚本,即 $SHELL。由于 shell 直接和计算机内核交互以及集成了很多常用内置命令,所以效率应该是高效的。
  2. 执行方式
    • bash script.sh 或 sh scripte.sh,文件本身没权限执行,没x权限,则使用的方法,或脚本未指定shebang。
    • 使用 绝对/相对 路径执行脚本,需要文件含有x权限。
    • source script.sh 或者 . script.sh ,代表 执行的含义,source等于点.。这种方式会保留当前环境变量。

Python脚本

不引入第三方库

  1. 如下代码所示,shebang指向的是path路径下的python3。
  2. 执行方式

    ./xxx.py
    python3 xxx.py

  3. if __name__ == "__main__": 限定了从命令行执行才会走,如果别的 python 文件调用则调用不到 main。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
import sys

def add_numbers(a, b):
return a + b

if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python sum_numbers.py <number1> <number2>")
sys.exit(1)

number1 = float(sys.argv[1])
number2 = float(sys.argv[2])

result = add_numbers(number1, number2)

print(f"The sum of {number1} and {number2} is {result}")

引入第三方库

  1. python 引入第三方库是通过 pip 安装,如果希望单独的 python 环境,这里需要创建其虚拟环境。
  2. 创建虚拟环境
    1
    2
    3
    # 使用 Python 的 venv 模块创建一个名为 my_virtual_env 的虚拟环境。
    # venv: 这是 Python 的一个标准库,用于创建虚拟环境。Python 3.3 版本以后,venv 成为了 Python 的一个标准库。
    python3 -m venv my_virtual_env
  3. 激活
    1
    source my_virtual_env/bin/activate
  4. 退出虚拟环境
    1
    .\my_virtual_env\Scripts\activate
  5. 安装第三方包
    1
    pip3 install numpy
  6. 设置脚本 shebang,指向虚拟环境
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
27
28
29
30
#!my_virtual_env/bin/python3
import numpy as np

def main():
# 创建一个3x3的随机矩阵
matrix_a = np.random.rand(3, 3)
print("Matrix A:")
print(matrix_a)
print()

# 计算矩阵的转置
transpose_a = np.transpose(matrix_a)
print("Transpose of Matrix A:")
print(transpose_a)
print()

# 计算矩阵的逐元素相乘
elementwise_product = np.multiply(matrix_a, transpose_a)
print("Element-wise product of Matrix A and its transpose:")
print(elementwise_product)
print()

# 计算矩阵的乘积
matrix_product = np.matmul(matrix_a, transpose_a)
print("Matrix product of Matrix A and its transpose:")
print(matrix_product)

if __name__ == "__main__":
main()

Ruby脚本

iOS 中的包管理工具 cocoapod,以及 fastlane 等工具都是 ruby 开发的,ruby 的版本以及虚拟环境管理相对 python 要繁琐一些。

不引入第三方库

  1. 设置 shebang 未系统当前 path 指向的 ruby。
  2. 执行方式

    ./xxx.rb
    ruby xxx.rb

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
27
#!/usr/bin/env ruby

def hello_world(name)
puts "Hello, #{name}!"
end

def add_numbers(a, b)
sum = a + b
puts "The sum of #{a} and #{b} is #{sum}."
end

# 获取命令行参数
command_line_args = ARGV

# 检查命令行参数数量
if command_line_args.length == 0
puts "Usage: ruby script.rb name"
exit
end

# 提取名字参数
name = command_line_args[0]

# 调用函数
hello_world(name)
add_numbers(1, 2)

引入第三方库

  1. 一下代码的执行方式

    1
    2
    3
    ./OptionParser.rb --name kkk -a 1 -b 2
    # 或者
    ruby OptionParser.rb --name kkk -a 1 -b 2
  2. rvm + .rvmrc + bundle 控制虚拟环境

    • rvm list,能看到当前系统有哪些版本的 ruby 以及该版本下的 gemset
    • .rvmrc,自动帮你切换到 ruby 的 gemset 了,可以理解成,帮你 rvm use xxx@xxx,其本质上就是更改 环境变量path;
    • bundle init,初始化 Gemfile,能够编辑依赖的第三方库也就是 gem 包,然后通过 bundler update 安装所需的第三方库,进入 bundler 环境;
    • gemset + ruby版本指定了.gem文件夹,但是.gem文件夹下还是可能有一个gem的多个版本,通过bundle环境来指定gem 版本;
    • 执行任何当前bundle环境下的ruby代码,都需要加上bundle exec前缀,bundle exec ruby main.rb  这样才能找到当前gemfile指定版本的ruby包;
    • bundle list 查看本bundle环境依赖的gems。
  3. 执行脚本的时候,可以通过 rvm use 指定环境,或者直接 cd 到.rvmrc目录。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env ruby

def printRbEnv
output = %x(gem env)
gem_paths = output.match(/- GEM PATHS:(.*?)(^\s*- GEM CONFIGURATION:|\z)/m)[1].strip
puts "Gem paths: #{gem_paths}"

end

printRbEnv

require 'optparse'

# 使用 OptionParser 解析命令行参数
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: ./OptionParser.rb [options]"

opts.on("-n NAME", "--name NAME", "Name to greet") do |name|
options[:name] = name
end

opts.on("-a A", "--a A", Integer, "First number to add") do |a|
options[:a] = a
end

opts.on("-b B", "--b B", Integer, "Second number to add") do |b|
options[:b] = b
end
end.parse!

# 检查命令行参数
if options[:name].nil?
puts "Please specify a name to greet."
exit
end

if options[:a].nil? || options[:b].nil?
puts "Please specify two numbers to add."
exit
end

# 加载第三方库
require 'colorize'

# 定义函数
def hello_world(name)
puts "Hello, #{name}!".colorize(:green)
end

def add_numbers(a, b)
sum = a + b
puts "The sum of #{a} and #{b} is #{sum}.".colorize(:blue)
end

# 调用函数
hello_world(options[:name])
add_numbers(options[:a], options[:b])

# ./OptionParser.rb --name kkk -a 1 -b 2

Swift脚本

Swift不是解释型语言,是编译型语言。可以通过swiftc filename.swift -o outputfile, 然后./outputfile执行。 Swift解释器是在 Swift 3 版本时引入的。 在 Swift 3 之前,Swift 只有编译器(swiftc), 它用于编译 Swift 代码生成可执行文件。Swift 3 引入了解释器(swift),它可以直接解释和执行 Swift 代码, 无需先生成可执行文件(但是并不代表是解释型语言吧???)。

这给 Swift 带来了几个好处:
● 开发效率更高 - 无需编译,就可以直接运行和测试代码
● REPL - 可以使用交互式的 Read-Eval-Print Loop 来测试和调试代码
● 交互式 Playgrounds - 可以在 Playground 中直接运行和调试代码
● 脚本语言 - 可以使用 Swift 作为脚本语言直接执行代码

不引入第三方库

  • 设置好 shebang
  • chmod +x swift_script.swift
  • ./swift_script.swift
1
2
3
4
5
6
#!/usr/bin/swift

import Foundation

print("Hello, World!")

引入第三方库

Swift Package Manager 是一个用于管理 Swift 代码包的工具,Swift 脚本通过这个管理第三方库。

  1. 创建一个Package.swift 文件

    1
    swift package init --type executable
  2. 编辑Package.swift 文件,注明依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // swift-tools-version:5.3
    import PackageDescription

    let package = Package(
    name: "MyScript",
    dependencies: [
    .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.0.0"),
    ],
    targets: [
    .target(
    name: "MyScript",
    dependencies: ["Alamofire"]),
    ]
    )
  3. 编辑脚本 main.swift

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import Alamofire
    import Foundation

    let argumentCount = CommandLine.argc
    let arguments = CommandLine.arguments

    print("Argument count: \(argumentCount)")

    for (index, argument) in arguments.enumerated() {
    print("Argument \(index): \(argument)")
    }
  4. 不能直接./MyScript/main.swift 执行(因为这种需要编译好),需要 build 和 run,之后会在.build隐藏文件夹下输出可执行文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 下载和编译依赖
    swift build

    # 运行应用
    swift run YourTargetName

    # 运行应用方式 2(拷贝到当前目录)
    ./YourTargetName