bash

bash

编译自:https://open source . com/article/18/5/you-don-know-bash-intro-bash-arrays。

作者:罗伯特·阿布哈利勒

译者:周佳玮

进入这个怪异而神奇的Bash数组世界。

虽然软件工程师经常使用命令行进行各种开发,但是命令行中的数组似乎总是一个模糊的东西(虽然不像常规运算符= ~)那么复杂晦涩。除了晦涩和可疑的语法,Bash数组实际上非常有用。

稍等,这是为什么?

写Bash相关的东西很难,但是如果写一篇像手册一样注重怪异语法的文章,就会很简单。不过放心,这篇文章的目的是让你不用看那该死的手册。

真实(通常是有用的)示例

为此,想象一个真实世界的场景,以及Bash可以如何提供帮助:您正在公司领导一项新工作,评估和优化内部数据管道的运行时间。首先你要做一个参数扫描分析,评估管道使用线程的情况。为了简单起见,我们把这个管道看作一个编译好的C++黑盒,我们唯一可以调整的参数就是用来处理数据的线程数量:。/管道-线程4。

基础

我们需要做的第一件事是定义一个数组来保存我们想要测试的- threads参数:

所有线程=(1 2 4 8 16 32 64 128)

在这个例子中,所有的元素都是数字,但是参数不一定是数字。Bash中的数组可以容纳数字和字符串,例如myArray=(1 2 “three” 4 “five)就是一个有效的表达式。就像Bash中的其他变量一样,确保赋值符号周围没有空方块。否则,Bash会将变量名作为程序执行,并将=作为程序的第一个参数。

现在我们已经初始化了数组,让我们解析它的一些元素。只需输入echo $allThreads,就可以看到它只输出第一个元素。

为了理解为什么会发生这种情况,我们需要回到上一步,回顾一下我们通常如何在Bash中输出变量。考虑以下场景:

type=”article “

echo“找到42个$类型”

如果我们得到的变量$type是一个单词,我们想在句尾加一个s。我们不能直接把s加到$type上,因为这样会把它变成另一个变量,$types。虽然我们可以使用像echo“Found 42”$ type“s”这样的代码变形,但是解决这个问题的最好方法是使用一个花括号:echo“Found 42 $ { type } s”,它允许我们说出Bash变量名的开始和结束位置(有趣的是,JaScript/ES6将变量和表达式注入模板文字的语法与这里相同)。

事实上,虽然Bash变量一般不使用花括号,但是数组中需要花括号。相反,这允许我们指定要访问的索引。例如,echo ${allThreads[1]}返回数组中的第二个元素。如果不写花括号,比如echo $allThreads[1],会导致Bash把[1]当作一个字符串,然后输出。

是的,Bash数组的语法很奇怪,但至少它们从0开始索引,不像某些语言(也就是你,R语言)。

遍历数组

在上面的例子中,我们直接用整数作为数组的索引。现在我们考虑另外两种情况:首先,如果我们想要数组中的第$i个元素,其中$i是表示索引的变量,我们可以像这样解析这个元素${ all threads[$ I]}。其次,为了输出一个数组的所有元素,我们用@符号代替数字索引(你可以把@作为all的符号):echo ${allThreads[@]}。

遍历数组元素

记住我上面说的,我们遍历$allThreads数组,并以每个值作为a – threads参数来启动管道:

对于${allThreads[@]}中的t;做

。/管道线程$t

完成的

遍历数组索引

接下来,考虑一种稍微不同的方法。我们可以遍历所有索引,而不是遍历所有数组元素:

为了我在${!all threads[@]};做

。/pipeline-threads $ { all threads[$ I]}

完成的

逐步:如前所述,${allThreads[@]}表示数组中的所有元素。前面加个感叹号就变成$ {!AllThreads[@]},返回数组索引列表(这里是0到7)。换句话说。for循环遍历所有索引$i,并从$allThreads中读取第$i个元素作为- threads选项的参数。

这个看起来很辣,你可能会奇怪我为什么要从头说起。这是因为有时您需要在循环中同时获得索引和相应的值。例如,如果要忽略数组中的第一个元素,使用索引可以避免在循环中创建额外的累积变量。

填充数组

到目前为止,我们已经能够使用给定的线程选项启动管道。现在假设以秒为单位的运行时间被输出到管道。我们希望捕获每次迭代的输出,然后将其保存在另一个数组中,这样我们最终可以随心所欲地操纵它。

一些有用的语法

在我们进入代码之前,我们需要引入更多的语法。首先,我们需要能够解析Bash命令的输出。使用这种语法,您可以做到:output=$(。/my_script.sh),它将命令的输出存储在变量$output中。

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

myArray+=(“新元素1”“新元素2”)

参数扫描

一切准备就绪,执行参数扫描的步骤如下:

所有线程=(1 2 4 8 16 32 64 128)

allRuntimes =()

对于${allThreads[@]}中的t;做

运行时=$(。/pipeline – threads $t)

all runtime+=($ runtime)

完成的

就是这个!

还有什么能做的?

在本文中,我们讨论了使用数组进行参数扫描的场景。我确信有很多理由使用Bash数组。这里有两个例子:

日志警告

在这个场景中,应用程序被分成几个模块,每个模块都有自己的日志文件。我们可以编写一个cron任务脚本,在模块中出现问题标志时向特定的人发送电子邮件:

#日志列表,出现问题时应该通知谁。

log paths =(” API . log ” ” auth . log ” ” Jenkins . log ” ” data . log “)

log emails =(“Jay @ email”“Emma @ email”“Jon @ email”“sophia @ email”)

#在每个日志中查找问题标志

为了我在${!日志路径[@]};

log=${logPaths[$i]}

利益相关者= $ {日志电子邮件[$i]}

numErrors = $(tail-n 100 ” $ log ” | grep ” ERROR ” | WC-l)

#如果最近发现5个以上的错误,警告负责人。

if[[” $ numErrors “-gt 5]];

然后

emailRecipient=”$stakeholder “

emailSubject= “警告:${log}显示异常级别的错误”

emailBody=”${numErrors}日志${log}中发现错误”

echo ” $ email body ” | mailx-s ” $ email subject ” ” $ email recipient “

船方不负担装货费用

完成的

API 查询

如果你想产生一些分析数据,分析你的用户评论最多的中型帖子。既然不能直接访问数据库,SQL不是我们考虑的,但是可以用API!

为了避免陷入关于API授权和令牌的冗长讨论,我们将使用JSONPlaceholder,一个面向公共的测试服务API。一旦我们查询了每个帖子并解析了每个评论者的邮箱,我们就可以将这些邮箱添加到我们的结果数组中:

endpoint = ” https://jsonplaceholder . typicode . com/comments “

所有邮件=()

#查询前10篇帖子

对于中的postId { 1..10};

#执行API调用以获取这篇文章评论者的电子邮件地址。

response=$(curl “${endpoint}?postId=${postId} “)

#使用jq将JSON响应解析成数组

所有邮件+=( $( jq ‘。[].电子邮件’ & lt& lt& lt” $response “))

完成的

注意,这里我使用jq工具从命令行解析JSON数据。关于jq的语法超出了本文的范围,但是我强烈建议您了解它。

正如您可能已经想到的,使用Bash数组在无数场景中都非常有用。希望本文中的例子能对你有所启发。如果你从自己的工作中发现了其他的例子,想分享一下,请在帖子下面评论。

请等等,还有很多东西!

因为我们在本文中讨论了很多关于数组语法的内容,所以这里总结一下我们所讨论的内容,包括一些还没有谈到的高级技巧:

语法效果arr=()创建一个空数组arr=(1 2 3)初始化数组${arr[2]}获取第三个元素${arr[@]}获取所有元素$ {!Arr[@]}获取数组索引${#arr[@]}计算数组长度,arr[0]=3,覆盖第一个元素,arr+=(4)加上值str=$(ls),将ls输出保存到字符串arr=( $(ls)),将ls输出文件保存到数组$ {arr [@]:

最后一点思考

正如我们所看到的,Bash数组的语法非常奇怪,但是我希望这篇文章能够让您相信它们非常有用。只要你理解了这些语法,你会发现Bash数组在未来会被频繁使用。

Bash 还是 Python?

问题是:什么时候应该使用Bash数组而不是其他脚本语法,比如Python?

对我来说,这完全取决于需求——如果仅仅通过调用命令行工具就可以立即解决问题,那么也可以使用Bash。但是有时候,当你的脚本属于一个更大的Python项目时,你也可以使用Python。

例如,我们可以使用Python来扫描参数,但是我们只需要编写一个Bash包装器:

导入子流程

所有线程= [1,2,4,8,16,32,64,128]

all _ runtime =[]

#用不同的线程号启动管道

对于所有线程中的t:

cmd = ‘。/pipeline – threads {}”。格式(t)

#使用子线程模块获取返回的输出

p =子流程。Popen(cmd,stdout =子进程。管道,壳=真)

output = p.communicate()[0]

all_runtimes.append(输出)

因为本例中无法避免命令行,所以可以先使用Bash。

羞耻的宣传时间

如果你喜欢这篇文章,这里还有很多类似的文章!在这里注册并加入OSCON。2018年7月17日,我将举办Bash在线编码研讨会,主题是你不知道的。没有幻灯片,没有门票,只有你和我在命令行中输入,探索Bash中的奇妙世界。

本文由【Medium】首发,转载时已获授权。

via:https://open source . com/article/18/5/you-dont-know-bash-intro-bash-arrays

作者:Robert Aboukhalil题目:lujun9972译者:BriFuture校对:wxy

本文由LCTT原创,并由Linux中国提供荣誉。

点击“了解更多”可访问文内链接

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

发表回复

登录后才能评论