正确允许在bash命令替换的分词 [英] Correctly allow word splitting of command substitution in bash

查看:150
本文介绍了正确允许在bash命令替换的分词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写的,维护和使用bash脚本的健康金额。我认为自己是一个庆典黑客努力总有一天会成为一个bash忍者(需要了解更多 AWK 第一)。一个庆典了解的最重要的特征/挫折是怎么报价,以及随后的参数扩展工作。这是有据可查和一个很好的理由,很多陷阱,错误和新手陷阱在神秘的存在世界报参数扩展和分词的。为此,该建议是双引号的一切,但如果我想发生分词是什么?

I write, maintain and use a healthy amount of bash scripts. I would consider myself a bash hacker and strive to someday be a bash ninja ( need to learn more awk first ). One of the most important feature/frustrations of bash to understand is how quotes, and subsequent parameter expansion, work. This is well documented, and for a good reason, many pitfalls, bugs and newbie-traps exist in the mysterious world of quoted parameter expansion and word splitting. For this reason, the advice is to "Double quote everything," but what if I want word splitting to occur?

多个风格 的导游我找不到命令替换后的安全和正常使用分词的一个例子。

In multiple style guides I can not find an example of safe and proper use of word splitting after command substitution.

我不需要帮助,得到这个命令的工作,但它似乎是违反既定的模式,如果你想给这个命令的反馈,请保持它在评论

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

该命令返回的替代品输出,如:

The command substitute returns output such as:

container-1 container-3 excitable-newton

这一个班轮使用命令替换吐出我的每一个运行的泊坞窗容器的名称和养活它们,用分词,作为单独的输入到泊坞窗统计命令,这需要容器名称的任意长度列表,还给一些信息他们。

This one-liner uses the command substitution to spit out the names of each of my running docker containers and the feeds them, with word splitting, as separate inputs to the docker stats command, which takes an arbitrary length list of container names and gives back some info about them.

如果我使用:

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

有将一个字符串中的换行分隔传递给泊坞窗统计容器名称。

There would be one string of newline separated container names passed to docker stats.

这似乎是,当我想分词一个很好的例子,但 shellcheck 不同意,这是不知何故不安全?是否有使用膨胀或替换后字分裂的既定的模式?

This seems like a perfect example of when I would want word splitting, but shellcheck disagrees, is this somehow unsafe? Is there an established pattern for using word-splitting after expansion or substitution?

推荐答案

从一个命令捕获输出,并把它传递到另一个安全的方式是暂时捕捉阵列的输出。这样就可以在任意分隔符和prevents无意拆分或通配符同时捕捉输出多个字符串到另一个命令传递分裂。

The safe way to capture output from one command and pass it to another is to temporarily capture the output in an array. This allows splitting on arbitrary delimiters and prevents unintentional splitting or globbing while capturing output as more than one string to be passed on to another command.

如果你想读一个空格分隔字符串到一个数组,使用读-a

If you want to read a space-separated string into an array, use read -a:

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

不同的是不带引号的扩张方式,这不扩大水珠。因此, foo的[酒吧] 不能命名为 foob ,或为空字符串,如果一个文件系统的条目被替换没有这样的文件系统项存在和 nullglob 外壳选项设置。 (同样, * 将不再与文件的当前目录列表代替)。

Unlike the unquoted-expansion approach, this doesn't expand globs. Thus, foo[bar] can't be replaced with a filesystem entry named foob, or with an empty string if no such filesystem entry exists and the nullglob shell option is set. (Likewise, * will no longer be replaced with a list of files in the current directory).

要细讲有关的行为:阅读-r -a 读取到的选项参数之后的第一个字符通过分隔符 - ð(如有),或NUL如果该选项参数为0字节,并拆分成果转化中的IFS基于字符的字段 - 一组,默认情况下,包含换行符,标签和空间;那么这些拆分的结果分配给一个数组。

To go into detail regarding behavior: read -r -a reads up to a delimiter passed as the first character of the option argument following -d (if given), or a NUL if that option argument is 0 bytes, and splits the results into fields based on characters within IFS -- a set which, by default, contains the newline, the tab, and the space; it then assigns those split results to an array.

此行​​为不有意义的变化基于壳本地配置,除IFS,可修改范围到单个命令。

This behavior does not meaningfully vary based on shell-local configuration, except for IFS, which can be modified scoped to the single command.

映射文件-t readarray -t 在行为上同样保持一致,同样建议在便携性约束不prevent其使用。

mapfile -t and readarray -t are similarly consistent in behavior, and likewise recommended if portability constraints do not prevent their use.

相反,阵列=($字符串)是更依赖于shell的配置和设置,的会表现不好,如果外壳的配置则留在默认值:

By contrast, array=( $string ) is much more dependent on the shell's configuration and settings, and will behave badly if the shell's configuration is left at defaults:


  • 使用 =阵列($字符串),如果设置-f 没有设置,每个字所创造分裂 $字符串被评估为水珠,与设在视禁用了javascript 设置行为进一步差异 nullglob (这将导致它的没有的扩展到任何内容导致空集,而不是扩展到水珠前$ p的默认$ pssion本身), failglob (这将导致该模式的没有的扩展到任何内容导致故障), extglob dotglob 及其他。

  • 使用阵列=($字符串),用于分割操作IFS的值不能以某种方式方便可靠地改变了作用域这个单一的操作。相比之下,可以运行 IFS =:读强制拆分只对•不用修改单值的范围IFS的价值;没有类似阵列=($字符串)存在,而无需存储和重新设置IFS(这是一个容易出错的操作;一些常用成语[如赋值为 oIFS 或类似的变量名称]操作相对于常见的场景,如未能在块的结尾再现未设置或空IFS意图而临时修改旨在适用)。

  • When using array=( $string ), if set -f is not set, each word created by splitting $string is evaluated as a glob, with further variances based in behavior depending on the shopt settings nullglob (which would cause a pattern which didn't expand to any contents to result in an empty set, rather than the default of expanding to the glob expression itself), failglob (which would cause a pattern which didn't expand to any contents to result in a failure), extglob, dotglob and others.
  • When using array=( $string ), the value of IFS used for the split operation cannot be easily and reliably altered in a manner scoped to this single operation. By contrast, one can run IFS=: read to force read to split only on :s without modifying the value of IFS outside the scope of that single value; no equivalent for array=( $string ) exists without storing and re-setting IFS (which is an error-prone operation; some common idioms [such as assignment to oIFS or a similar variable name] operate contrary to intent in common scenarios, such as failing to reproduce an unset or empty IFS at the end of the block to which the temporary modification is intended to apply).

这篇关于正确允许在bash命令替换的分词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆