尽管软件工程师经常在开发的许多方面都使用命令行,但是数组可能是命令行中比较模糊的功能之一(尽管不如regex运算符=~那么模糊)。 但是除了晦涩难懂的语法外, Bash数组可能非常强大。

等等,为什么呢?

关于Bash的写作具有挑战性,因为将一篇文章转为侧重于语法奇数的手册非常容易。 不过,请放心,本文的目的是避免让您成为RTFM。

一个真实的(实际有用的)例子

为此,让我们考虑一个真实的场景以及Bash如何提供帮助:您正在为公司做出新的努力,以评估和优化内部数据管道的运行时间。 第一步,您要进行参数扫描以评估管道对线程的利用程度。 为了简单起见,我们将管道视为已编译的C ++黑匣子,其中唯一可以调整的参数是为数据处理保留的线程数: ./pipeline --threads 4

基础

我们要测试的--threads参数:

 allThreads = ( 1 2 4 8 16 32 64 128 ) 

在此示例中,所有元素都是数字,但并非必须如此-Bash中的数组可以包含数字和字符串,例如, myArray=(1 2 "three" 4 "five")是有效表达式。 与其他Bash变量一样,请确保在等号周围不留空格。 否则,Bash会将变量名称视为要执行的程序,并将=作为其第一个参数!

现在我们已经初始化了数组,让我们检索它的一些元素。 您会注意到,仅执行echo $allThreads只会输出第一个元素。

要了解为什么会发生这种情况,让我们退后一步,回顾一下我们通常在Bash中输出变量的方式。 请考虑以下情形:

type = "article"
echo "Found 42 $type "

假设变量$type以单数名词的$type提供给我们,我们想在句子的末尾添加s 。 我们不能简单地在$type添加s ,因为那样会将其变成另一个变量$types 。 而且,尽管我们可以利用诸如echo "Found 42 "$type"s"代码扭曲,但是解决此问题的最佳方法是使用花括号: echo "Found 42 ${type}s" ,这使我们能够告诉Bash变量名称的开始和结束位置(有趣的是,这与JavaScript / ES6中用于在模板文字中注入变量和表达式的语法相同)。

事实证明,尽管Bash变量通常不需要大括号,但数组需要它们。 反过来,这允许我们指定要访问的索引,例如echo ${allThreads[1]}返回数组的第二个元素。 不包括方括号,例如echo $allThreads[1] ,会导致Bash将[1]视为字符串并echo $allThreads[1]输出。

是的,Bash数组的语法很奇怪,但至少与其他某些语言不同(我在看着您R ),它们是零索引的。

遍历数组

尽管在上面的示例中,我们在数组中使用了整数索引,但让我们考虑以下两种情况:首先,如果我们想要数组的$i -th元素,其中$i是包含索引的变量如果感兴趣,我们可以使用以下方法检索该元素: echo ${allThreads[$i]} 。 其次,要输出数组的所有元素,我们将数字索引替换为@符号(您可以将@代表all ): echo ${allThreads[@]}

遍历数组元素

考虑到这一点,让我们遍历$allThreads和发射的每个值管道--threads

for t in ${allThreads[@]} ; do
. / pipeline --threads $t
done

遍历数组索引

接下来,让我们考虑一种稍微不同的方法。 除了遍历数组元素 ,我们还可以遍历数组索引

for i in ${!allThreads[@]} ; do
. / pipeline --threads ${allThreads[$i]}
done

让我们分解一下:正如我们在上面看到的, ${allThreads[@]}代表数组中的所有元素。 添加一个感叹号使其成为${!allThreads[@]}将返回所有数组索引的列表(在我们的示例中为0到7)。 换句话说, for循环遍历所有索引$i并从$allThreads读取$i -th个元素以设置--threads参数的值。

这在眼睛上要严厉得多,因此您可能想知道为什么我一开始就引入它。 那是因为有时候您需要同时知道索引和循环中的值,例如,如果您想忽略数组的第一个元素,则使用索引可以避免创建额外的变量,然后在循环内递增。

填充数组

到目前为止,我们已经能够为每个感兴趣的--threads启动管道。 现在,假设流水线的输出是以秒为单位的运行时间。 我们希望在每次迭代时捕获该输出,并将其保存在另一个数组中,以便最后可以对它进行各种操作。

一些有用的语法

但是在深入研究代码之前,我们需要引入更多语法。 首先,我们需要能够检索Bash命令的输出。 为此,请使用以下语法: output=$( ./my_script.sh ) ,它将命令的输出存储到变量$output

我们需要的语法的第二位是如何将刚检索到的值附加到数组中。 这样做的语法看起来很熟悉:

 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作业脚本以向合适的人发送电子邮件:

# List of logs and who should be notified of issues
logPaths = ( "api.log" "auth.log" "jenkins.log" "data.log" )
logEmails = ( "jay@email" "emma@email" "jon@email" "sophia@email" )

# Look for signs of trouble in each log
for i in ${!logPaths[@]} ;
do
log = ${logPaths[$i]}
stakeholder = ${logEmails[$i]}
numErrors =$ ( tail -n 100 " $log " | grep "ERROR" | wc -l )

# Warn stakeholders if recently saw > 5 errors
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查询

假设您要生成一些分析,以了解哪些用户在您的“中型”帖子中评论最多。 由于我们没有直接的数据库访问权限,因此SQL是不可能的,但是我们可以使用API​​!

为了避免深入讨论API身份验证和令牌,我们将使用JSONPlaceholder (一个面向公众的API测试服务)作为我们的端点。 一旦查询了每个帖子并检索了发表评论的每个人的电子邮件,就可以将这些电子邮件追加到结果数组中:

endpoint = "https://jsonplaceholder.typicode.com/comments"
allEmails = ( )

# Query first 10 posts
for postId in { 1 .. 10 } ;
do
# Make API call to fetch emails of this posts's commenters
response =$ ( curl " ${endpoint} ?postId= ${postId} " )

# Use jq to parse the JSON response into an array
allEmails+= ( $ ( jq '.[].email' <<< " $response " ) )
done


请注意,我在使用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[@]:s:n} 检索starting at index 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 = [ ]

# Launch pipeline on each number of threads
for t in all_threads:
cmd = './pipeline --threads {}' .format ( t )

# Use the subprocess module to fetch the return output
p = subprocess.Popen ( cmd, stdout =subprocess.PIPE, shell =True )
output = p.communicate ( ) [ 0 ]
all_runtimes.append ( output )


由于在此示例中没有解决命令行问题,因此最好直接使用Bash。

该换个无耻的插头了

如果您喜欢这篇文章,那么还有更多的来历! 在此处注册以参加OSCON ,我将在2018年7月17日举行现场编码研讨会“ 你不知道Bash ”。没有幻灯片,没有点击器-只是你我在命令行中打字,探索了奇妙的世界巴什。

本文最初出现在Medium上 ,经许可重新发布。

翻译自: https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays

您不知道Bash:Bash阵列简介相关推荐

  1. Mac zsh切换bash bash切换zsh

    切换bash    ---->>>chsh -s /bin/bash 切换zsh      ------->>>chsh -s /bin/zsh

  2. linux替换bash,bash脚本_输入输出和管道、替换

    以cat为例,功能是从文件读数据,送到stdout. # cat tmp back-loop.sh cgiselect 要是没有文件作为命令的参数,那么就要从stdin输入,实际上就是将界面输入的字符 ...

  3. bash脚本编程入门_Bash编程入门

    bash脚本编程入门 对Unix的最初希望之一是,它将使日常的计算机用户能够微调其计算机以适应其独特的工作风格. 在过去的几十年中,对计算机定制的期望已经降低,许多用户将他们收集的应用程序和网站视为他 ...

  4. 认识 BASH Shell

    认识 BASH Shell 切换解析度为 800x600 最近更新日期:2005/08/30 文字模式 (command line) 这种指令下达的方式,在 Linux 里面,其实就相当于是 bash ...

  5. mac上的终端bash命令

    (一) Bourne-Again Shell简介 mac上的终端使用的是Bourne-Again Shell命令,简称bash bash是GNU组织开发和推广的一个项目,是对Bourne shell的 ...

  6. 鸟哥的Linux私房菜(基础篇)- 第十一章、认识与学习 BASH

    第十一章.认识与学习 BASH 最近升级日期:2009/08/25 在 Linux 的环境下,如果你不懂 bash 是什么,那么其他的东西就不用学了!因为前面几章我们使用终端机下达命令的方式,就是透过 ...

  7. 如何能在git bash中使用mvn命令_使用Github Actions完成CI/CD工作

    在本文中,我们将介绍如何使用 Github Actions 自动化开发部署工作流,使版本控制和 CI/CD 平台在同一个地方完成. 自2019年开始,github便提供了CI/CD工具,对于publi ...

  8. bash 命令提示符_命令行上每天的Bash提示

    bash 命令提示符 作为许多Linux和Unix变体的默认外壳,Bash包括各种未被充分利用的功能,因此很难决定讨论什么. 最终,我决定专注于使日常活动变得更轻松的Bash技巧. 作为顾问,我看到了 ...

  9. linux 测试本地端口是否打开,关于bash:有效测试Linux是否打开了端口?

    从bash脚本中,如何快速确定端口445是否在服务器上处于打开/侦听状态. 我已经尝试了几种选择,但是我想要一些快速的方法: 1. lsof -i :445(以秒为单位) 2. netstat -an ...

最新文章

  1. linux和unix文件没有创建时间,Linux中没有文件创建时间的概念
  2. python工程师薪资坑吗-python能到什么程度
  3. Linux内核源代码分析——fork()原理多进程网络模型
  4. 转载 cglib代理和java代理
  5. centos7每天定时删除备份mysql文件
  6. java set iterator_Java中的TreeSet的iterator()方法 Java.util.TreeSet.iterator() - Break易站
  7. 大公司青睐的50款开源工具
  8. matlab工序能力分析,《MATLAB编程与系统仿真》课程考核说明
  9. YAML_11 when条件判断
  10. 黑盒测试 ------ 等价类划分法
  11. VS启动项目时一个奇葩问题
  12. 流计算技术实战 - CEP
  13. Storm入门之第6章一个实际的例子
  14. Windows Installer Cleanup Utility 下载和使用说明
  15. APK大小查看、定义、反编译、如何安装解压
  16. 网络七层协议,五层协议概述
  17. RAID Introduction
  18. 2019一键清空朋友圈_微信一键删除好友软件(2019微信批量删除好友最快速有效的方法)...
  19. 室内 Beacon定位室外 GPS 定位 大型场馆融合定位方案
  20. Sparrow 开发板化身电脑音量调节器

热门文章

  1. spring中事务失效的几种情况
  2. 使用Jackson将一个对象转换成一个JSON字符串
  3. Java虚拟机栈详解
  4. Spring 4.3 的新功能和增强
  5. eclipse package explorer视图中怎么让default package不显示?
  6. 解决在iOS8环境下,当用户关闭定位服务总开关时,无法将APP定位子选项加入定位权限列表的问题...
  7. 关于ThreadPool.RegisterWaitForSingleObject和WaitHandle的应用介绍
  8. oracle的clob字段导致线上应用无响应问题及解决
  9. 解决 wildfly(jboss) 启动报错:'findstr' 不是内部或外部命令
  10. Python读写文件(附完整模块化代码)