Arrays 为什么在包含空格的情况下,无法将全局或大括号从变量扩展到数组

Arrays 为什么在包含空格的情况下,无法将全局或大括号从变量扩展到数组,arrays,bash,variables,glob,Arrays,Bash,Variables,Glob,我正在尝试使用内部bash globs和大括号从变量到数组的扩展机制 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/testfile

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

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")
declare -a expanded=([0]="./tmp2/tmp2 3/testfile./tmp2/tmp2 3/testfile2./tmp2/tmp2 3/testfile3./tmp2/tmp2 3/testfile4./tmp2/tmp2 3/tmp231")
路径已展开,但结果为false,并且由于IFS而被拆分

现在报价为$(eval)

结果:

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")
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似乎没有效果

是否有其他替代方法可供使用(如read或mapfile,或者是否可以转义空格字符)

我发现了这个问题,但对空间一无所知

是否有任何方法可以使用相同的方法将包含有空格或无空格的全局或大括号展开参数的变量展开为数组,而在这些参数包含空格时不进行分词


亲切问候

不要使用
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
的默认值包含空格、制表符和换行符。如果不希望空格、制表符和换行符被视为单词之间的分隔符,则需要修改默认值。

不要使用
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
的默认值包含空格、制表符和换行符。如果不希望空格、制表符和换行符被视为单词之间的分隔符,则需要修改默认值。

BTW,请注意,通常
array=($(…任何…)
被视为反模式;请参见.BTW,注意通常
array=($(…任何东西…)
被视为反模式;您好,非常感谢您的回答。它适用于全局扩展,但不适用于大括号扩展。用一种常用的方法或函数,是不可能得到两次计算结果的。当这对globs有效时,对牙套等就不再有效了。您好,非常感谢您的回答。它适用于全局扩展,但不适用于大括号扩展。用一种常用的方法或函数,是不可能得到两次计算结果的。当这对globs起作用时,对大括号等就不再起作用了。