首页 > 解决方案 > 为什么当包含空格时,从变量到数组的 glob 或大括号扩展是不可能的

问题描述

我正在尝试使用从变量到数组的内部 bash glob 和大括号扩展机制。

path='./tmp2/tmp23/*'
expanded=($(eval echo "$(printf "%q" "${path}")"))

结果:

declare -- path="./tmp2/tmp23/*"
declare -a expanded=([0]="./tmp2/tmp23/testfile" [1]="./tmp2/tmp23/testfile2" [2]="./tmp2/tmp23/testfile3" [3]="./tmp2/tmp23/testfile4" [4]="./tmp2/tmp23/tmp231")

这是有效的。(我在 ./tmp2/tmp23 文件夹中有 4 个文件 testfileX 和 1 个文件夹)数组索引中的每个文件/文件夹。

现在,如果我的路径包含空格:

path='./tmp2/tmp2 3/*'
expanded=($(eval echo "$(printf "%q" "${path}")"))

结果

declare -- path="./tmp2/tmp2 3/*"
declare -a expanded=([0]="./tmp2/tmp2" [1]="3/")

由于IFS calvary,没有任何工作被扩展并且路径被分割。

现在具有包含空格但没有 glob 的相同路径:

path='./tmp2/tmp2 3/'
expanded=($(eval echo "$(printf "%q" "${path}"*)")) => added glob here outside ""

结果:

declare -a expanded=([0]="./tmp2/tmp2" [1]="3/testfile./tmp2/tmp2" [2]="3/testfile2./tmp2/tmp2" [3]="3/testfile3./tmp2/tmp2" [4]="3/testfile4./tmp2/tmp2" [5]="3/tmp231")

路径已扩展,但由于 IFS,结果为错误且分裂。

现在引用 $(eval)

expanded=("$(eval echo "$(printf "%q" "${path}"*)")")

结果:

declare -a expanded=([0]="./tmp2/tmp2 3/testfile./tmp2/tmp2 3/testfile2./tmp2/tmp2 3/testfile3./tmp2/tmp2 3/testfile4./tmp2/tmp2 3/tmp231")

现在所有扩展都在同一个数组索引内完成。

如果没有空格,为什么 glob 或大括号扩展在变量内部起作用?

为什么当有空间时这不再起作用了。完全相同的代码,但只是一个空格。大括号或大括号扩展需要在双引号之外。eval 似乎没有效果。

是否有其他替代方法可以使用(作为读取或映射文件,或者是否可以转义空格字符)?

我发现了这个问题how-to-assign-a-glob-expression-to-a-variable-in-a-bash-script但没有关于空格的问题。

有没有办法使用相同的方法将包含带空格或不带空格的 glob 或大括号扩展参数的变量扩展为数组,当它们包含空格时不进行分词?

亲切的问候

标签: arraysbashvariablesglob

解决方案


不要使用eval. 不要使用子shell。只要清楚IFS

path='./tmp2/tmp2 3/*'

oIFS=${IFS:-$' \t\n'} IFS='' # backup prior IFS value
expanded=( $path )           # perform expansion, unquoted
IFS=$oIFS                    # reset to original value, or an equivalent thereto

当您执行不带引号的扩展时,会按顺序发生两件不同的事情:

  • 在变量中找到的所有字符$IFS都用于将字符串拆分为单词
  • 然后将每个单词扩展为一个单独的 glob。

的默认值IFS包含空格、制表符和换行符。如果您不希望将空格、制表符和换行符视为单词之间的分隔符,则需要修改该默认值。


推荐阅读