Bash 中的空格和字符串

2021-07-30 18:16:23

上周在工作中,我正在编写 bash 脚本,其中一部分需要获取 Kubernetes 节点的状态。具体来说,我正在运行此命令:作为脚本的一部分,我使用 cut 通过执行以下操作来提取第二列的值:#!/bin/bash result = $(kubectl get nodes node-0 | tail -n 1 ) state = $( echo $result | cut -d ' ' -f2 ) echo $state 在第三行,我将 kubectl get nodes node-0 的输出通过管道传输到尾部并仅存储输出的第二行,因为第一行包含列标题并且在这种情况下没有用。在第 4 行,我使用 cut 命令按字符空间拆分单词,由 -d ' ' 标志指示,并提取第二列的值,由 -f2 标志指示。当我运行脚本时,我看到了预期的输出:但是,shellcheck 抱怨脚本的第 4 行(它也抱怨最后一行,但这与本文无关):在 test.sh 第 4 行:state=$ (echo $result | cut -d ' ' -f2) ^-- SC2086:双引号以防止通配和分词。

但令我惊讶的是,我现在所拥有的只是一个空字符串作为输出。为了调试这个,我通过以下方式打印了 $result 的值:我复制了这个并运行它直接在 bash shell 上剪切 -d ' ' -f2 。我得到了预期的输出——就绪。 $ result="node-0 Ready <none> 3d v1.11.1"$ state=$(echo "${result}" | cut -d ' ' -f2)$ echo $stateReady 我能够得到想要的输出时间。我在我公司的 Slack 中询问,最终发现如果我直接在 shell 中运行以下命令: $ result=$(kubectl get nodes node-0 | tail -n 1)$ echo "$result"node-0 Ready <none> 3d v1.11.1 注意区别了吗?不同之处在于 $result 周围存在双引号。当我们将变量用双引号括起来时,我们是在强制 bash 按原样打印变量并引用 linuxdocumentation 项目:使用双引号保留所有包含的字符的字面值,除了美元符号、反引号(向后单引号,`` ) 和反斜杠。

现在问题已经确定,解决方案很简单——在使用 cut 之前需要挤出列之间的额外间距:我从这个练习中学到的另一个重要教训是,当处理字符串时,纯文本格式不是最好的选择。 kubectl 可以输出 yaml 和 json。我更喜欢 json,因为它更容易用肉眼解析,我可以使用 jq 以编程方式操作 json 输出。因此,我能够将我的脚本最小化为一行:-o json 标志指示 Kubernetes API 返回响应 json,我们将结果通过管道传递给 jq 进行进一步处理,其中过滤器特定于 Kubernetes。通常认为将 bash 变量包装在 {} 周围是一种很好的做法。因此,使用 echo ${result} 代替 echo "$result" 更安全,可以帮助避免涉及字符串扩展的错误。如果你对 Kubernetes 感兴趣,kubectl 还支持 -ojsonpath,它可以让你直接指定 json 过滤器并返回最小化的输出而不是整个 json 字符串。我尝试使用 jsonpath 但就我而言,我注意到负索引引起了恐慌。我还没有在 Kubernetesproject 的问题跟踪器上提交关于此的问题,并且打算在我使用最新的 Kubernetes 组件验证这一点后提交。