gpt4 book ai didi

bash - 在 bash 中正确地允许命令替换的分词

转载 作者:行者123 更新时间:2023-11-29 09:18:05 26 4
gpt4 key购买 nike

我编写、维护和使用了大量的 bash 脚本。我会认为自己是一名 bash 黑客,并努力有朝一日成为一名 bash 忍者(需要先学习更多 awk)。要理解 bash 的最重要的特性/挫折之一是引号和随后的参数扩展是如何工作的。这是 well documented ,并且有充分的理由,在引用参数扩展和分词的神秘世界中存在许多陷阱、错误和新手陷阱。出于这个原因,建议是“对所有内容进行双引号”,但是如果我希望发生分词怎么办?

multiple style guides我找不到在命令替换后安全和正确使用分词的示例。

使用不带引号的命令替换的正确方法是什么?

示例:

我不需要帮助让这个命令正常工作,但它似乎违反了既定模式,如果您想对此命令提供反馈,请在评论中保留它

docker stats $(docker ps | awk '{print $NF}' | grep -v NAMES)

命令替代返回如下输出:

container-1 container-3 excitable-newton

这个单行代码使用命令替换吐出我正在运行的每个 docker 容器的名称,并通过分词将它们作为单独的输入提供给 docker stats 命令,该命令需要一个任意长度的容器名称列表,并返回一些关于它们的信息。

如果我使用:

docker stats "$(docker ps | awk '{print $NF}' | grep -v NAMES)"

将有一串换行符分隔的容器名称传递给 docker stats

这似乎是我何时需要分词的完美示例,但是 shellcheck不同意,这在某种程度上是不安全的吗?在扩展或替换后是否有使用分词的既定模式?

最佳答案

从一个命令捕获输出并将其传递给另一个命令的安全方法是临时捕获数组中的输出。这允许在任意定界符上进行拆分,并防止在将输出捕获为多个字符串以传递给另一命令时出现意外拆分或通配。

如果要将空格分隔的字符串读入数组,请使用read -a:

read -r -a names < <(docker ps | awk '{print $NF}' | grep -v NAMES)
printf 'Found name: %s\n' "${names[@]}"

与不带引号的扩展方法不同,这不会扩展 glob。因此,foo[bar] 不能替换为名为 foob 的文件系统条目,或者如果不存在这样的文件系统条目且 nullglob< 则不能替换为空字符串 shell 选项已设置。 (同样,* 将不再替换为当前目录中的文件列表)。


详细了解行为:read -r -a 读取作为选项参数的第一个字符传递的定界符,紧跟在 -d 之后(如果给定) , 或者 NUL 如果该选项参数为 0 字节,并根据 IFS 中的字符将结果拆分为字段——默认情况下,该集合包含换行符、制表符和空格;然后它将这些拆分结果分配给一个数组。

此行为不会根据 shell 本地配置而有意义地发生变化,但 IFS 除外,它可以在单个命令的范围内进行修改。

mapfile -treadarray -t 在行为上同样一致,如果可移植性限制不妨碍它们的使用,同样推荐使用。


相比之下,array=( $string ) 更依赖于 shell 的配置和设置,如果 shell 的配置保留为默认值, 将表现不佳:

  • 当使用array=( $string ) 时,如果未设置set -f,则评估通过拆分$string 创建的每个单词作为一个 glob,根据 shopt 设置 nullglob 的行为进一步变化(这会导致一个模式没有扩展到任何内容导致一个空集,而不是默认扩展到 glob 表达式本身),failglob(这会导致一个没有扩展到任何内容的模式导致失败)、extglobdotglob 和其他。
  • 当使用 array=( $string ) 时,用于拆分操作的 IFS 的值无法以仅限于此单个操作的方式轻松可靠地更改。相比之下,可以运行 IFS=: read 以强制 read 仅在 : 上拆分,而无需修改 IFS 范围之外的值那个单一的值(value);如果不存储和重新设置 IFS,则不存在 array=( $string ) 的等效项(这是一个容易出错的操作;一些常见的习语 [例如分配给 oIFS 或一个类似的变量名称]在常见情况下的操作与意图相反,例如未能在临时修改旨在应用的 block 的末尾重现未设置或空的 IFS)。

关于bash - 在 bash 中正确地允许命令替换的分词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37931155/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com