1

I'm trying to use internal bash globs and braces expansion mechanism from a variable to an array.

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

results:

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")

This is working. (I have 4 file testfileX and 1 folder in the ./tmp2/tmp23 folder) Each file/folder inside an index of the array.

Now if my path contains spaces:

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

Results

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

Not working nothing is expanded and path is splitted due to IFS calvary.

Now with same path containing spaces but without glob:

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

Results:

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")

Path is expanded but results are false and splitted due to IFS.

Now with a quoted $(eval)

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

Results:

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

Now all expansion is done inside the same array index.

Why glob or braces expansion works inside a variable if there is no space ?

Why this is not working anymore when there is a space. Exactly the same code but just a space. Globs or braces expansion need to be outside double quotes. eval seems to have no effects.

Is there any other alternative to use (as read or mapfile or is it possible to escape space character) ?

I found this question how-to-assign-a-glob-expression-to-a-variable-in-a-bash-script but nothing about spaces.

Is there any way to expand a variable which contains globs or braces expansion parameters with spaces or without spaces to an array using the same method without word splitting when they contain spaces ?

Kind Regards

moocan
  • 111
  • 2
  • 11
  • BTW, note that in general `array=( $(...anything...) )` is considered an antipattern; see [BashPitfalls #50](http://mywiki.wooledge.org/BashPitfalls#hosts.3D.28_.24.28aws_....29_.29). – Charles Duffy May 20 '20 at 03:27

1 Answers1

0

Don't use eval. Don't use a subshell. Just clear 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

When you perform an unquoted expansion, two separate things happen in order:

  • All the characters found in the $IFS variable are used to split the string into words
  • Each word is then expanded as a separate glob.

The default value of IFS contains the space, the tab and the newline. If you don't want spaces, tabs and newlines to be treated as delimiters between words, then you need to modify that default.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Hello, Many thanks for your answer. It works well with glob expansion but do not work with braces expansion. It is impossible to get something which could evaluate the twice with a common method or function. When this is working for globs this do not work anymore for braces and so on. – moocan May 22 '20 at 19:58