摆脱瞎忙人生,从自动化作起。做为一名职场人,有没有为忘发汇报邮件而烦恼过,有没有因繁忙的工做而丢三落四过;做为一名程序员,有没为天天早上 pull 代码后漫长的编译时间而烦躁过,有没有为各类无脑的系统配置而无聊过。天天咱们都在这些重复枯燥的事情中,浪费着咱们宝贵的生命。如何提升工做效率成为咱们相当重要的事情 ,这篇文件将会带领咱们经过自动化的方式,来有效地提升咱们的工做效率。php
本文大部内容是基于 MacOS 环境的,非 Mac 党也能够借鉴其中的一些思想。html
在谈自动化以前,咱们先来了解下 Shell Script 这门有点古老而又很是强大的脚本语言,首先咱们要分清一个概念性的问题,Shell 和 Shell Script 之间的区别:git
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户经过这个界面访问操做系统内核的服务。程序员
Shell 脚本(Shell Script),是一种为 Shell 编写的脚本程序。shell
这里先给你们科普下概念,但大多的时候,咱们都统称 Shell Script 为 shell,文中的其它地方的 "shell" 指的一样是 Shell Script。关于 shell 的基础语法,并不在本文的讨论范围内,但在开始实践如何经过 shell 来提升咱们工做效率以前,我来我简单介绍 shell 几个经常使用而又强大的功能。编程
管道是 shell 中很是经常使用的功能之一,它容许不一样脚本、命令之间互相传递数据,例如:xcode
ls | grep 'pars'
复制代码
该命令意思是将 ls 输出的内容传递到 grep 'pars' 命令,grep 会把包含 'pars' 的内容过虑出来。咱们再举个栗子,经过 shell 获取 git 仓库里中的当前分支名:bash
currentBranch=`git branch | grep "*"`
currentBranch=${currentBranch/* /}
复制代码
大多数 UNIX 系统命令从终端接受输入并将所产生的输出发送回终端。一个命令一般从一个叫标准输入的地方读取输入,默认状况下是终端。一样,一个命令一般将其输出写入到标准输出,默认状况下也是终端。若是你须要修改输入或输出,就须要使用到重定向功能。网络
命令 | 说明 |
---|---|
command > file | 将输出重定向到 file。 |
command < file | 将输入重定向到 file。 |
command >> file | 将输出以追加的方式重定向到 file。 |
输出重定向,指将一条命令的输入位置从新定义,举个例子:session
ls > ls.txt
复制代码
ls 输出结果应显示在终端,而上面命令将 ls 的输出结果写到 ls.txt 这个文件中。须要注意,用 > 重定向到 ls.txt 文件默认是覆盖的,若是须要用追加的方式写入文件,则须要使用 >>:
pwd >> ls.txt
复制代码
输入重定向:
pbcopy < ls.txt
复制代码
上面的命令的意思是,将 ls.txt 的内容复制到粘贴板。
之因此简单介绍这几个经常使用功能,是由于若是不懂这些功能,会影响理解下面的内容。若是你对 shell 脚本不熟悉,建议你抽空学习一下,平常工做中,用到 shell 的频率仍是很是高的。
简单聊完 shell 这几个经常使用而又强大的功能后,咱们开始实践如何经过 shell 来提升工做效率。
因我平常工做的须要,电脑须要配置双网卡,这里以配置电脑的双网卡为例,先附上部分配置脚本:
inside_ssid=\"WIFINAME\"; en0_ssid=\"$(networksetup -getairportnetwork en0 | sed 's/.*[:] //')\" if [ \"$en0_ssid\" != \"$inside_ssid\" ]; then echo -n \"请先将内网卡设置到$inside_ssid\" else inside_adaptor_index=\"$(netstat -rn|grep default |grep en0 -n | cut -d: -f1)\" if [ \"$inside_adaptor_index\" = 1 ]; then echo -n \"请开启外网卡,且服务顺序在内网卡前\" else inside_gateway=\"$(netstat -rn|grep default |grep en0|awk '{print $2}')\" sudo echo \"刷新配置成功\"; sudo route -n delete -net 10.*.*.128; sudo route -n delete -net 10; sudo route -n delete -net 30; sudo route -n add -net 10.*.*.128 $inside_gateway; sudo route -n add -net 10 $inside_gateway; sudo route -n add -net 30 $inside_gateway fi fi 复制代码
这里不解析这些脚本的做用,咱们的重点在于如何进一步提升效率上。因为每次重启电脑,都需从新配置双网卡,才能正常同时使用内外网,也就是说,每次重启电脑须要从新执行一次这个操做。懒是人类的天性,若是咱们连执行一下脚本也不想干的话,那么咱们须要怎么作呢?
咱们能够在在电脑开机时设置自启动任务。首先我须要建立一个 plist 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LaunchOnlyOnce</key>
<true/>
<key>Label</key>
<string>com.dengyonghao.xxxx</string>
<key>ProgramArguments</key>
<array>
<string>/Users/xxxxx/work/Tools/xxxx.sh</string>
</array>
</dict>
</plist>
复制代码
简单解析下各个 key 的做用,LaunchOnlyOnce 指定开机后只执行一次,不指定则每隔一段时间就会执行一次。Label 指定该 plist 的惟一标识。ProgramArguments 则是设置执行脚本的路径,指向你想要启动时自动执行的脚本路径。
完成上面操做后,把建立的 plist 文件拷贝到 ~/Library/LaunchAgents
目录下,表示仅对当前用户生效,而后执行:
sudo launchctl load ~/Library/LaunchAgents/xxxxxx.plist
复制代码
将这个文件注册到系统中,而后电脑启动时就会自动执行,完成双网上的配置。这里有一个问题,若是启动时自动执行上面的双网卡配置脚本,真的能正常运行吗?
事实上是不行的,由于 sudo
命令须要你输入管理员密码,但你并无地方输入,因此是没有权限进行这些操做的。故咱们须要用到 Apple Script,从而引出下一节的内容,这里先附上 Apple Script 脚本:
do shell script " inside_ssid=\"WIFINAME\"; en0_ssid=\"$(networksetup -getairportnetwork en0 | sed 's/.*[:] //')\" if [ \"$en0_ssid\" != \"$inside_ssid\" ]; then echo -n \"请先将内网卡设置到$inside_ssid\" else inside_adaptor_index=\"$(netstat -rn|grep default |grep en0 -n | cut -d: -f1)\" if [ \"$inside_adaptor_index\" = 1 ]; then echo -n \"请开启外网卡,且服务顺序在内网卡前\" else inside_gateway=\"$(netstat -rn|grep default |grep en0|awk '{print $2}')\" sudo echo \"刷新配置成功\"; sudo route -n delete -net 10.*.*.128; sudo route -n delete -net 10; sudo route -n delete -net 30; sudo route -n add -net 10.*.*.128 $inside_gateway; sudo route -n add -net 10 $inside_gateway; sudo route -n add -net 30 $inside_gateway fi fi" with administrator privileges
复制代码
这里只是用 Apple Script 来提供一个图形界面来要求用户先输入管理员密码,才容许他继续执行脚本。脚本使用了 Apple Script,故开机启动项的 plist 的文件也要作相应的变化:
<key>ProgramArguments</key>
<array>
<string>osascript</string>
<string>/Users/xxxx/work/Tools/xxxx.scpt</string>
</array>
复制代码
关于 Apple Script 的内容将在下一节详细介绍,这里咱们先思考一个问题:设置开机执行后,就能解决上面说的痛点了吗?
事实上并不能解决全部问题,好比说,开机的时候外置网卡没有插上,那么自动执行的脚本就会配置失败,这时就又回到最初的场景,须要咱们去找到这个脚本文件,而后经过终端执行。那么咱们能够怎么去优化这个流程呢?咱们带着这个问题,继续后面的内容,而后来再回来解决它。
在给团队成员分享的过程当中,队友们提出 sudo 能够明文设置管理员密码,不须要每次运行时手动输入,命令格式以下:
echo password | sudo -S xxxxxxxxx
复制代码
须要注意的是,明文保存密码存在泄露的风险,建议使用这种方式前先评估风险。
AppleScript 是 Apple 建立的脚本语言,用于自动执行 Macintosh 操做系统及其许多应用程序操做的语言。能够用来控制运行于 macOS 上的程序,以及 macOS 自己的部份内容。你能够建立脚原本自动执行重复性任务,或组合多个可编写脚本的应用程序的功能来建立复杂的工做流程。
咱们使用 AppleScript 建立备忘录、管理网络、处理图像、备份文件等等,AppleScript 是功能很是强大的自动化工具,它内置于 macOS 系统中,经过 脚本编辑器 应用来编写和运行,任何用户均可以避免费使用它。
macOS 中默认已经提供编写 AppleScript 的工具:脚本编辑器,咱们能够经过应用程序中找到并启动它。
咱们打开脚本编辑器并选择新建文稿,输入如下内容:
tell application "Finder" to open the startup disk
复制代码
点击运行后,系统会在桌面打开一个新的Finder窗口,显示启动盘的内容,这里咱们已经完成了第一个 AppleScript 脚本。
再举个栗子,经过 AppleScript 打开或者关闭 Xcode:
tell application "Xcode"
activate
--quit
end tell
复制代码
从上面脚本能够看出,AppleScript 和天然语言很是接近,编写起来十分简单,但至于如何去学习 AppleScript 的语法,这里不会多作讲解,有兴趣的同窗能够经过官方文档学习。
Dash,程序员神器之一,强烈推荐一波。
咱们在学习一门新的编程语言时,当在使用某个 API 遇到问题时,最靠谱的解决方法不是 Google,而是先看下它的文档 。咱们能够经过 Dash 下载 AppleScript 文档,遇到问题时,咱们能够快速查阅,而且 AppleScript 的文档并很少,空闲时能够通读一次(估计2-3小时),逐步加深对 AppleScript 的了解。
下面咱们直接开始实操,来实现一个自动提醒发送重点项目进度的工具,除了提醒功能外,该工具还会自动帮你建立邮件模块,包括收件人、主题、内容模板等,咱们来看实现脚本:
on callback()
tell (current date) to get (its year as integer) & "-" & (its month as integer) & "-" & day
set dataText to the result as text
set mailTitle to "-重点项目进度" as text
set mailTitle to dataText & mailTitle
tell application "Microsoft Outlook"
set newMessage to make new outgoing message with properties {subject:mailTitle, content:"Dear xx:<br/>如下是个人重点项目进度状况,详细请查看附件:<br/><br/><br/>Best Regards"}
make new recipient at newMessage with properties {email address:{name:"xxx", address:"xxxx@pingan.com.cn"}}
#make new cc recipient at newMessage with properties {email address:{name:"Name", address:"test@example.com"}}
open newMessage
end tell
end callback
display dialog "又到周一了,赶忙发重点项目进度" buttons {"如今发", "一会发"} default button 1
if the button returned of the result is "如今发" then
callback()
end if
复制代码
这里咱们经过 AppleScript 访问 Microsoft Outlook 并自动生成邮件模板,以上脚本只给邮件内容填充了模块,但实际上还能够实现自动把你的重点项目进度excel统计表附件进来,再进一步的话,能够直接经过 AppleScript 读取 excel 的内容,而后填充到邮件内容中,只要你在完成重点项目内容后,及时更新 excel 统计表中的内容,那么到每周一发重点项目的时候,你只须要一个命令就能够自动完成汇报邮件。
咱们完成了自动生成邮件模板的功能后,还需提供自动提醒的功能,关于自动提醒功能,咱们可使用 mac 的启动服务来实现,和自动配置双网上的方式如出一辙,咱们建立相应的 plist 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.dengyonghao.viproject</string>
<key>ProgramArguments</key>
<array>
<string>osascript</string>
<string>/Users/dengyonghao/work/Tools/viproject.scpt</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>1</integer>
<key>Minute</key>
<integer>30</integer>
<key>Hour</key>
<integer>10</integer>
</dict>
</dict>
</plist>
复制代码
须要注意的是这里多了 StartCalendarInterval 这个 key,这个 key 是用来控制你脚本的执行周期或者时间的,这里设置为每周一上午 10:30 时就会自动执行脚本。
AppleScript 的内容就简单介绍到这里,总之 AppleScript 很是强大,具体怎么使用,建议空闲时共同探讨一下。
Automator 是苹果公司为 macOS 系统开发的一款软件,只要经过点击拖拽鼠标等操做就能够将一系列动做组合成一个工做流程,从而帮助你自动的(可重复的)完成一些复杂的工做。Automator 其实是一些列动做组合在一个工做流文档里,而后按顺序去执行这些动做,与咱们上面因此说的脚本很是相似,但 Automator 能够横跨多个程序进行,并提供图形界面进行操做,用户操做起来很是方便。
关于 Automator,咱们能够经过实现脚本转应用的例子进行了解,首先咱们打开 macOS 自带的 Automator,选新建文稿-->应用程序-->实用工具-->运行xxx脚本,而后把你的脚本填写进去,而后保存生成一个应用。生成的应用默认是 Automator 的图标,若是你想去改变图标,则能够右击应用—>显示包内容-->Contents-->Resources,而后把 AutomatorApplet.icns 替换成你想要的图标就能够了。
咱们能够把经常使用的脚本生成应用,放到经常使用的位置,双击一下就能执行,这样也是挺爽歪歪的,可是这并非我想要的,我想在任意的地方法均可以快速执行,因此这里就引入了 Alfred 这个工具了。
关于 Automator 网上有很多教程,想进一步了解的同窗,推荐阅读:Automator 简单介绍及入门玩法 | Matrix 精选
Alfred 是什么?可能只能说是神器,不吹不黑,但这里我是不会讲如何去使用 Alfred 的,没有用过的小伙伴自行百度。
Workflow 又是什么梗呢,Workflow 工做流的意思,它表示把多个事件联合在一块儿,造成一个连贯的动做。
这里省略成千上万的字,须要你自行去学习 Alfred 的使用,或许它 --> Google 能够帮你
讲到这里,咱们能够思考下文章开始配置双网卡的那个问题,估计你们都会有更好的方法了。
咱们能够把配置双网卡的 AppleScript 写成 Alfred 的一个 workflows。好比我设置了 Alfred 的快捷打开键为 double com,双网上配置 workflows 的 keyword 为 doublenet,这样的话,我能够在电脑的任意界面输入:double com + doublenet + 回车,便可完成双网卡的配置。
上面介绍了一堆的工具,看到这里,可能仍是一脸懵逼,如今咱们来经过实操,来把它们一锅炖了。
做为一名程序员,从 Finder 目录跳转到 iTerm 的场景很是多,大多数时候咱们都是经过拖动目录到 iTerm,而后 cd 进去,效率很是低,经过学习上面的内容,咱们能够经过 AppleScript + Hotkey 快速在 iTerm 中打开当前 Finder 的目录。
首先咱们能够经过 AppleScript 获取当前 Finder 窗口的目录:
tell application "Finder"
set pathFile to selection as text
set pathFile to get POSIX path of pathFile
--防止目录存在空格跳转不了
set pathFile to quoted form of pathFile
end tell
复制代码
而后经过 iTerm 提供的 AppleScript API 跳转到指定目录:
ell application "Finder"
set pathFile to selection as text
set pathFile to get POSIX path of pathFile
--防止目录存在空格跳转不了
set pathFile to quoted form of pathFile
set pathFile to "cd " & pathFile
--set the clipboard to pathFile
tell application "iTerm"
create window with default profile
tell current session of current window
write text pathFile
end tell
end tell
end tell
复制代码
咱们完成脚本后,则能够经过 Alfred 配置一个 Hotkey,用来快速执行该脚本:
我这里面配置的 Hotkey 是 com + T,因此我只要按下 com + T,则会自动打开 pwd 在当前 Finder 窗口的目录下的 iTerm。
每次开周会时,在一周回顾环节中,老是拼命回顾这周我作了那些事情,特别是分享亮点和不足的时候,就各类词穷。这里介绍一个很是有效的方法,就是天天记一记,周会不纠结。其实这个方法你们都知道,只是你们都懒得记,或者是没有找到一个好的工具,我曾经用印象笔记记录过一段时间,但用了一段时间后,发现每当脑子忽然灵光一闪,有好的 idea 并想记录下来时,然而印象笔记并无打开,接着本身又懒得打开来记录了。为了不再次发生这种事情,我经过 notes + applescript + alfred 来实现一个速记事情工做流:
on alfred_script(q)
tell application "Notes"
tell account "iCloud"
tell (current date) to get (its year as integer) & "-" & (its month as integer) & "-" & day
set dataText to the result as text
set mailTitle to dataText & "-速记"
make new note at folder "PANote" with properties {name:mailTitle, body:q}
end tell
end tell
end alfred_script
复制代码
这段 applescript 的意思是把 alfred 获取到内容,保存到 PANote 文件下。如今咱们实现了快速记录的功能后,咱们还须要快速来查找,咱们也是经过 applescript + alfred 来实现:
use framework "Foundation"
property NSRegularExpressionSearch : a reference to 1024
property NSString : a reference to current application's NSString property NSJSONSerialization : a reference to current application's NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application's NSUTF8StringEncoding on run argv set output to {} tell application "Notes" set folderNames to name of folders in default account repeat with folderIndex from 1 to number of folders in default account set folderName to item folderIndex of folderNames if folderName is "PANote" then set currentFolder to (a reference to item folderIndex of folders in default account) set noteIDs to id of notes of currentFolder set noteNames to name of notes of currentFolder set noteBodies to body of notes of currentFolder repeat with i from 1 to count of noteIDs set noteBody to (NSString's stringWithString:(item i of noteBodies))
set noteBody to (noteBody's stringByReplacingOccurrencesOfString:"<[^>]*>| " withString:" " options:NSRegularExpressionSearch range:{0, noteBody's |length|()})
set noteBody to (noteBody's stringByReplacingOccurrencesOfString:"^ +| +$| +(?= )|" withString:"" options:NSRegularExpressionSearch range:{0, noteBody's |length|()}) as text
set match to (item i of noteNames) & " " & folderName & " " & noteBody
if length of noteBody is less than 100 then
set subtitle to noteBody
else
set subtitle to text 1 thru 100 of noteBody
end if
set subtitle to folderName & " | " & subtitle
set end of output to {title:(item i of noteNames), arg:(item i of noteIDs), subtitle:subtitle, match:match, uid:(item i of noteNames)}
end repeat
end if
end repeat
end tell
set output to {|items|:output}
set output to NSJSONSerialization's dataWithJSONObject:output options:0 |error|:(missing value) set output to (NSString's alloc()'s initWithData:output encoding:NSUTF8StringEncoding) as text return output end run 复制代码
这里的代码看起来很是多,其实原理很是简单,首先遍历 default account 下的全部文件夹,而后找到 PANote 这个文件夹,把查找到的内容格式化后传给 output,alfred 会帮咱们把 output 的内容以列表形式展现出来。当咱们选中展现中的内容时,咱们还须要在 Notes 里面打开相应的内容,故咱们再实现一个打开 Notes 的脚本:
on alfred_script(q)
tell application "Notes"
show note id q
end tell
end alfred_script
复制代码
须要注意的是,这个方法 id 参数是从上一段代码中的:
output to {title:xxxx, arg:xxxx, subtitle:xxxx, match:xxxx, uid:xxxx}
复制代码
arg 里面获取的,这个是 alfred 定义的格式,咱们无须关心他是如何实现的,只要按照 alfred 的规范来传参就能够了。
天天早上我到公司的时候,首先是去洗杯打水,而后拉代码编译,接着等待漫长的编译时间,日复一日,风雨无阻~~但在某个发呆的瞬间,忽然有一个想法,为啥不让系统在我到公司前把代码编译好呢,我到公司的时候就能够直接工做,不用等待漫长的编译过程了。
有了这种想法,就要动手去作,咱们把任务一步步地拆分,首先是拉代码,在拉代码前,咱们须要先检查仓库是否干净,而后默默写下如下脚本:
checkGitWorkspaceClean() {
echo "Action - checkGitWorkspaceClean"
if [ $# -lt 1 ]; then
echo "One param is required - the check dir.";
exit 1;
fi
if [ ! -d $1 ]; then
echo "The dir does not exist - $1";
exit 1;
fi
currentDir=`pwd`
cd $1
result=`git status -s`
if [ -n "$result" ]; then
echo "The git workspace is not clean - $1"
exit 1
fi
cd $currentDir
}
复制代码
这里经过 git status -s
命令来判断当前仓库是不是可拉取代码状态,若是不可拉取就直接退出。
接着下一步是拉取当前全部分支的最新代码,咱们须要获取分支名并拉取该分支的最新代码:
pullLatestCode() {
echo "Action - pullLatestCode"
if [ $# -lt 1 ]; then
echo "One param is required - the check dir.";
exit 1;
fi
if [ ! -d $1 ]; then
echo "The dir does not exist - $1";
exit 1;
fi
currentDir=`pwd`
cd $1
currentBranch=`git branch | grep "*"`
currentBranch=${currentBranch/* /}
`git pull git pull --rebase origin ${currentBranch}`
cd $currentDir
}
复制代码
有没有以为这些代码很熟悉,其实在 shell 那节都有介绍过的,这里只是把上面说的内容应用到实际的场景中而已。
拉取完成代码后,咱们就能够经过 xcodebuild 编译代码,xcodebuild 参数能够参考 apple 官方帮助文档,这里你默认使用模拟器进行编译:
buildProject() {
echo "Action - pullLatestCode"
if [ $# -lt 1 ]; then
echo "One param is required - the check dir.";
exit 1;
fi
if [ ! -d $1 ]; then
echo "The dir does not exist - $1";
exit 1;
fi
currentDir=`pwd`
cd $1
xcodebuild -workspace ${PARS_PROJECT_NAME}.xcworkspace -scheme ${PARS_PROJECT_NAME} -sdk iphonesimulator build
cd $currentDir
}
复制代码
这样咱们整个拉取和编译流程均可以经过代码来实现了,可是在编译代码前,应该先检查下仓库是否有冲突,若是有冲突就不开始编译,因此正确的流程是:
checkGitWorkspaceClean $PARS_PROJECT_DIR
pullLatestCode $PARS_PROJECT_DIR
checkGitWorkspaceClean $PARS_PROJECT_DIR
buildProject $PARS_PROJECT_DIR
复制代码
当不能正常完成编译时,能够经过 AppleScript 显示一些可视化的提示,好比弹窗之类的,这一些优化依据我的习惯添加就能够,不过多讲解。
若是你以为在终端编译不够直观,没法直接看到编译进度,咱们则能够经过 AppleScript 来优化代码编译流程,直接调用 Xcode 来编译或者运行代码:
tell application "Xcode"
open "/Users/xxxxx/xxxx/xxxxx/xxxxx.xcworkspace"
set workspaceDocument to workspace document "xxxxx.xcworkspace"
repeat 120 times
if loaded of workspaceDocument is true then
exit repeat
end if
delay 1
end repeat
if loaded of workspaceDocument is false then
error "Xcode workspace did not finish loading within timeout."
end if
set actionResult to run workspaceDocument
repeat
if completed of actionResult is true then
exit repeat
end if
delay 1
end repeat
end tell
复制代码
到这,已经把最关键的拉取和编译代码的功能讲完,至于如何定时执行,在上文已经详细介绍过,这里不重复讲解。可是定时任务存在一个不太方便的问题,就是当你电脑关机或者休眠时,这个定时任务就不会启动。设置电脑一直待机不休眠也不太好,毕竟公家财产也是要爱护的,比较折中的方法是把这个脚本写成 alfred 的 workflows,咱们到公司时,能够先花 1-2 秒时间来执行这个 workflows,而后再去洗杯打水吃早餐之类的,等你把乱七八糟的事情搞定了,代码也快编译好了。
在给团队成员分享的过程当中,队友们就自动拉代码并编译时机方面,提出了更好的方案:天天晚上12点(你们都下班的时候)时执行脚本,执行完成后经过脚本让电脑休眠,从而避免电脑长时间待机。
本文简单分享如何经过工具,来处理平常工做中遇到的一些烦琐的事情 ,经过使用脚本等方式来实现自动化,从而提高我的的工做效率。这里仅提供一个思路和一些例子,至于如何发挥,就得看你本身如何去使用这些工具了,总之,工具是越用越合手的。
个人小专栏 ,若是喜欢,能够订阅一波。