我们需要的第二个语法是如何把我们刚刚解析的值添加到数组中。完成这个任务的语法看起来很熟悉:
myArray+=( "newElement1" "newElement2" )
参数扫描
万事具备,执行参数扫描的脚步如下:
allThreads=(1 2 4 8 16 32 64 128)
allRuntimes=()
for t in ${allThreads[@]}; do
runtime=$(./pipeline --threads $t)
allRuntimes+=( $runtime )
done
就是这个了!
还有什么能做的?
这篇文章中,我们讲过使用数组进行参数扫描的场景。我敢保证有很多理由要使用 Bash 数组,这里就有两个例子:
日志警告
本场景中,把应用分成几个模块,每一个都有它自己的日志文件。我们可以编写一个 cron 任务脚本,当某个模块中出现问题标志时向特定的人发送邮件:
# 日志列表,发生问题时应该通知的人
logPaths=("api.log" "auth.log" "jenkins.log" "data.log")
logEmails=("jay@email" "emma@email" "jon@email" "sophia@email")
# 在每个日志中查找问题标志
for i in ${!logPaths[@]};
do
log=${logPaths[$i]}
stakeholder=${logEmails[$i]}
numErrors=$( tail -n 100 "$log" | grep "ERROR" | wc -l )
# 如果近期发现超过 5 个错误,就警告负责人
if [[ "$numErrors" -gt 5 ]];
then
emailRecipient="$stakeholder"
emailSubject="WARNING: ${log} showing unusual levels of errors"
emailBody="${numErrors} errors found in log ${log}"
echo "$emailBody" | mailx -s "$emailSubject" "$emailRecipient"
fi
done
API 查询
如果你想要生成一些分析数据,分析你的 Medium 帖子中用户评论最多的。由于我们无法直接访问数据库,SQL 不在我们考虑范围,但我们可以用 API!
endpoint="https://jsonplaceholder.typicode.com/comments"
allEmails=()
# 查询前 10 个帖子
for postId in {1..10};
do
# 执行 API 调用,获取该帖子评论者的邮箱
response=$(curl "${endpoint}?postId=${postId}")
# 使用 jq 把 JSON 响应解析成数组
allEmails+=( $( jq '.[].email' <<< "$response" ) )
done
注意这里我是用 jq 工具 从命令行里解析 JSON 数据。关于 jq 的语法超出了本文的范围,但我强烈建议你了解它。
请等等,还有很多东西!
由于我们在本文讲了很多数组语法,这里是关于我们讲到内容的总结,包含一些还没讲到的高级技巧:
语法效果arr=()创建一个空数组arr=(1 2 3)初始化数组${arr[2]}取得第三个元素${arr[@]}取得所有元素${!arr[@]}取得数组索引${#arr[@]}计算数组长度arr[0]=3覆盖第 1 个元素arr+=(4)添加值str=$(ls)把 ls 输出保存到字符串arr=( $(ls) )把 ls 输出的文件保存到数组里${arr[@]:s:n}取得从索引 s 开始的 n 个元素
最后一点思考
正如我们所见,Bash 数组的语法很奇怪,但我希望这篇文章让你相信它们很有用。只要你理解了这些语法,你会发现以后会经常使用 Bash 数组。
Bash 还是 Python?
问题来了:什么时候该用 Bash 数组而不是其他的脚本语法,比如 Python?
对我而言,完全取决于需求——如果你可以只需要调用命令行工具就能立马解决问题,你也可以用 Bash。但有些时候,当你的脚本属于一个更大的 Python 项目时,你也可以用 Python。
比如,我们可以用 Python 来实现参数扫描,但我们只用编写一个 Bash 的包装:
import subprocess
all_threads = [1, 2, 4, 8, 16, 32, 64, 128]
all_runtimes = []
# 用不同的线程数字启动管线
for t in all_threads:
cmd = './pipeline --threads {}'.format(t)
# 使用子线程模块获得返回的输出
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
output = p.communicate()[0]
all_runtimes.append(output)
由于本例中没法避免使用命令行,所以可以优先使用 Bash。
羞耻的宣传时间
如果你喜欢这篇文章,这里还有很多类似的文章! 在此注册,加入 OSCON ,2018 年 7 月 17 号我会在这做一个主题为 你所不了解的 Bash 的在线编码研讨会。没有幻灯片,不需要门票,只有你和我在命令行里面敲代码,探索 Bash 中的奇妙世界。
via: https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays
閱讀更多 Linux技術 的文章