我编写,维护和使用健康数量的bash脚本.我认为自己是一个重击黑客,并努力有一天成为一个bash忍者(需要先了解更多awk).bash要理解的最重要的特征/挫折之一是引用和后续参数扩展如何工作.这是有据可查的,并且有充分的理由,在引用参数扩展和分词的神秘世界中存在许多陷阱,错误和新手陷阱.出于这个原因,建议是"双引用一切",但如果我想要分词发生怎么办?
在多个 样式 指南中,我找不到在命令替换后安全和正确使用单词拆分的示例.
我不需要帮助让这个命令工作,但它似乎违反了已建立的模式,如果你想对这个命令给出反馈,请保留在评论中
docker stats $(docker ps | awk '{print $NF}' | grep -v NAMES)
Run Code Online (Sandbox Code Playgroud)
命令替换返回输出,例如:
container-1 container-3 excitable-newton
Run Code Online (Sandbox Code Playgroud)
这个单行使用命令替换来吐出每个正在运行的docker容器的名称,并使用单词拆分将它们作为docker stats命令的单独输入提供给它们,该命令采用任意长度的容器名称列表并返回一些信息关于他们.
如果我用过:
docker stats "$(docker ps | awk '{print $NF}' | grep -v NAMES)"
Run Code Online (Sandbox Code Playgroud)
将传递一行换行符分隔的容器名称docker stats.
这似乎是一个完美的例子,当我想要分词时,但是shellcheck不同意,这有点不安全吗?在扩展或替换之后是否存在使用分词的既定模式?
从一个命令捕获输出并将其传递给另一个命令的安全方法是临时捕获数组中的输出.这允许在任意分隔符上进行拆分,并在捕获输出时防止无意拆分或通配,因为多个字符串要传递给另一个命令.
如果要将以空格分隔的字符串读入数组,请使用read -a:
read -r -a names < <(docker ps | awk '{print $NF}' | grep -v NAMES)
printf 'Found name: %s\n' "${names[@]}"
Run Code Online (Sandbox Code Playgroud)
与不带引号扩展的方法不同,这不会扩展整体.因此,如果不存在这样的文件系统条目并且设置了shell选项,foo[bar]则不能替换为名为的文件系统条目foob,或者使用空字符串替换nullglob.(同样,*将不再替换当前目录中的文件列表).
要详细了解行为:read -r -a读取作为选项参数的第一个字符-d(如果给定)传递的分隔符,或者如果该选项参数是0字节则传入NUL,并将结果拆分为基于IFS中字符的字段 - - 默认情况下包含换行符,制表符和空格的集合; 然后它将这些拆分结果分配给一个数组.
除了IFS之外,此行为在shell本地配置方面没有任何意义上的变化,IFS可以作为单个命令进行范围修改.
mapfile -t并且readarray -t在行为上具有相似的一致性,并且如果可移植性约束不妨碍其使用,则同样建议使用.
相比之下,array=( $string )更加依赖于shell的配置和设置,并会表现不好,如果壳的配置是在默认左:
array=( $string ),如果set -f未设置,则通过拆分创建的每个单词将$string被评估为glob,并根据shopt设置进一步根据行为进行差异nullglob(这将导致未扩展为任何内容的模式导致空集,而不是扩展到glob表达式本身的默认值,failglob(这将导致一个模式没有扩展到任何内容导致失败)extglob,dotglob和其他.array=( $string ),用于拆分操作的IFS值不能以作用于此单个操作的方式轻松可靠地更改.相比之下,人们可以IFS=: read强制read仅在:s 上拆分而不修改IFS值在该单个值范围之外; 没有array=( $string )存储和重新设置IFS的存在没有等价物(这是一个容易出错的操作;一些常见的习惯用法[例如赋值oIFS或类似的变量名]在常见情况下与意图相反,例如未能重现未设置或在临时修改要应用的块的末尾处的空IFS).| 归档时间: |
|
| 查看次数: |
686 次 |
| 最近记录: |