你所不了解的 Bash:关于 Bash 数组的介绍

我们需要的第二个语法是如何把我们刚刚解析的值添加到数组中。完成这个任务的语法看起来很熟悉:

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


分享到:


相關文章: