Homebrew 配合 shell 脚本自动安装软件

换电脑很烦恼,最麻烦的就是软件安装和环境配置,环境还好,配置文件复制过来开箱即用,软件着实麻烦,每次都得不停的输入重复命令来安装,痛定思痛,写了个 shell 脚本调用 homebrew 安装软件,从此可以带着 install.sh 随便换机器了。(闲的 🥚 疼,手动 🌹🐔)


也可以使用Homebrew自带的备份工具Homebrew Bundle

  1. 备份:brew bundle dump --describe --force --file="~/xxx/Brewfile"
  2. 恢复:brew bundle --file="~/xxx/Brewfile"

XX 叨叨

又换电脑?哪有钱,打工人穷得很。自用的 MacBook Pro2015 算下来已经快 6 年了,用着倒也还行,但每次听它的风扇呼呼转就心里紧张,清灰,换硅脂,一顿操作下来,不太理想,可能是性能瓶颈了,又困于囊中羞涩,遂入手了一台迷你小主机,几个月 Windows 用下来,始终不顺手,然后就闲置当作了家庭娱乐机,“买前生产力,买后爱奇艺”。

最近,MacBook Pro 的风扇又开始呼呼转了(供暖了),盯着小主机看了看,打起了黑苹果的主意,善用搜索引擎加上不耻下问(咳咳),还算顺利的用上了黑苹果,真香!

头疼的事情又来了,安装软件 ➕ 配置环境,于是就抽空写了个 shell 脚本,调用 homebrew 来自动安装软件。

shell 脚本

构思
  1. homebrew-core 核心库中软件有限,很多软件需要其他 tap,所以需要一个数组用来存储 taps

    1
    source=()
  2. 软件也不少(废话,不然还用得着脚本?),同样需要一个数组:

    1
    programs=()
  3. 既然用了数组,就需要使用循环来取出内容并调用 homebrew:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 获取需要的 tap
    for tap in ${source[@]}
    do
    echo "brew tap $tap" && brew tap $tap
    done

    # 安装软件
    for app in ${programs[@]}
    do
    echo "brew install $app" && brew install $app
    done

  4. 有些软件在安装过程中需要输入密码,没问题,调用 expect 即可;

  5. 基本上就这样了,开始实现吧;

实现
  1. 创建 install.sh,按照构思写入基本结构;

  2. tap 部分的代码不用动,直接填入需要的 tap 即可;

  3. 安装方面,需要先实现自动输入密码功能,由于需要使用 expect 且解释器不同,所以新建 autoinput.sh 来实现自动填写密码的功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/usr/bin/expect

    ## 预设的电脑密码
    set password "你的电脑密码"

    ## 超时时间,单位:秒
    set timeout -1

    ## 接收传递的应用名称
    set program [lindex $argv 0]

    ## 安装
    spawn brew install $program

    ## 需要密码则输入
    expect {
    "*assword*:" { send "$password\r"; exp_continue; }
    eof
    }
  4. 然后实现 install.sh 中的调用:

    1
    2
    3
    4
    for app in ${programs[@]}
    do
    ./autoinput.sh $app
    done
  5. 填入 tap 和软件,测试一下,完活儿了;

优化
  1. 加上注释,空行,软件列表等内容,一共 100 来行的代码居然分成两个文件,合并;

  2. 合并的话只需要修改调用 expect 的代码即可,也就是安装软件部分,其他不动:

    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
    for app in ${programs[@]}
    do
    ## 嵌入 expect 自动输入密码
    # 声明按照 expect 解析下面的脚本,遇到 EOF 则停止
    /usr/bin/expect <<-EOF

    ## 预设的电脑密码
    set password "你的电脑密码"

    ## 超时时间,单位:秒,-1 表示永不过期
    set timeout -1

    ## 安装应用
    spawn brew install $app

    ## 需要密码则输入
    expect {
    "*assword*:"
    { send "$password\r"; exp_continue; }
    eof
    }
    # 对应 /usr/bin/expect <<-EOF
    EOF
    done

  3. 完整代码:

    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    #!/bin/bash

    ## 电脑需要有 expect 命令,请使用下面命令自查:👇
    # whereis expect

    # 算了,还是加上安装 expect 吧,反正已安装会自动跳过(辛苦 brew 了)
    echo "brew install expect" && brew install expect

    ## 使用的 tap
    # 按需写入,以下是我使用的 tap
    source=(
    # 你使用的 tap 请写在这里
    # 以下内容可以删除
    homebrew/cask
    homebrew/cask-fonts # font-fira-code
    homebrew/cask-drivers # logitech-options
    homebrew/cask-versions # clashx-pro
    adoptopenjdk/openjdk # adoptopenjdk
    bigwig-club/brew # upic
    # 删除截止
    )

    # 获取需要的 tap
    for tap in ${source[@]}
    do
    echo "brew tap $tap" && brew tap $tap
    done

    ## 需要安装的软件列表
    programs=(
    # 你需要的软件请写在这里
    )

    ## 遍历软件列表并安装应用
    # 某些程序在安装时需要输入电脑密码
    for app in ${programs[@]}
    do
    ## 嵌入 expect 自动输入密码
    # 声明按照 expect 解析下面的脚本,遇到 EOF 则停止
    /usr/bin/expect <<-EOF

    ## 预设的电脑密码
    set password "你的电脑密码"

    ## 超时时间,单位:秒,-1 表示永不过期
    set timeout -1

    ## 安装应用
    # 说明:
    # brew install xxx 是用来安装命令行应用的
    # 安装图形化应用对应的命令是:brew install --cask xxx
    # 所以遇到既有命令行也有图形化的应用时,需要说明安装应用的来源
    # 如:brew install homebrew/cask/wireshark

    spawn brew install $app

    ## 调试命令:显示 expect 执行的详细信息
    # exp_internal 1

    ## 需要密码则输入
    # 匹配"spawn brew install $app"的返回结果
    # 如果以'Password:'或'password:'结尾则输入用户密码
    expect {
    # 模糊匹配,也可以使用 expect -re
    "\[P\|p\]assword:$"

    # $ 符号需要转义
    # 发送密码后需要继续安装
    { send "\$password\r"; exp_continue; }

    # expect 无需等待
    expect eof
    }
    # 对应 /usr/bin/expect <<-EOF
    # 命令段结束
    EOF
    done
食用
  1. 首先确定自己的电脑有 expect,没有就brew install expect 已添加自动安装 expect;

  2. 将使用的 tap 写入source=()的括号内,举个 🌰:

    1
    2
    3
    4
    5
    source=(
    tap1
    tap2 tap3 tap4
    )

    数组元素之间用空白字符分隔,如:空格 / 制表符等等;

  3. 将使用的软件名写入programs=()的括号内(还是数组,So…):

    1
    2
    3
    4
    5
    programs=(
    qq
    qqmusic
    qqlive tencent-metting tencent-lemon
    )
  4. 是的,你没看错,shell 中的数组确实是用圆括号()表示的,而函数的定义又很常见;

  5. 软件名必须是 homebrew 中的名称,而不是软件自身的名称,举 🌰:

    软件名homebrew 中的名字
    爱奇艺qiyimedia
    阿里云盘adrive
    微信WeChat

    有些软件的名字确实很奇怪,无法用自身的软件名去推测,而有些则很友好;

    不知道的先用brew search xxx搜索一下;

  6. macOS 系统版本众多,自 10.15 后软件必须是 64 位,所以有些软件会装不上而出错,很正常;

    如:爱奇艺,要求系统必须是 10.15 及以上;

  7. 善用搜索引擎;

打完,收工!