How to assign a glob expression to a variable in a Bash script?

后端 未结 8 1454
渐次进展
渐次进展 2020-12-08 02:21

When the following two lines of code are executed in a bash script, \"ls\" complains that the files don\'t exist:

dirs=/content/{dev01,dev02}
ls -l $dirs


        
相关标签:
8条回答
  • 2020-12-08 02:31

    I think it is the order of expansions:

    The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.

    So if your variable is substituted, brace expansion doesn't take place anymore. This works for me:

    eval ls $dirs
    

    Be very careful with eval. It will execute the stuff verbatimly. So if dirs contains f{m,k}t*; some_command, some_command will be executed after the ls finished. It will execute the string you give to eval in the current shell. It will pass /content/dev01 /content/dev02 to ls, whether they exist or not. Putting * after the stuff makes it a pathname-expansion, and it will omit non-existing paths:

    dirs=/content/{dev01,dev02}*
    

    I'm not 100% sure about this, but it makes sense to me.

    0 讨论(0)
  • 2020-12-08 02:34

    This isn't filename globbing, this is brace expansion. The difference is subtle, but it exists - in filename globbing you would only receive existing files as a result, while in brace expansion you can generate any kind of string.

    http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion

    http://www.gnu.org/software/bash/manual/bashref.html#Filename-Expansion

    Now, this is what worked for me:

    #!/bin/sh
    dirs=`echo ./{dev01,dev02}`
    ls $dirs
    
    0 讨论(0)
  • 2020-12-08 02:34

    Since you want to glob files, you shouldn't use brace expansions. Using brace expansion in this case is an antipattern and definitely the wrong tool for the job.

    What you want is extended globbing:

    shopt -s extglob # likely already set in interactive shells
    
    dirs=/content/@(dev01|dev02)
    ls $dirs
    
    0 讨论(0)
  • 2020-12-08 02:37

    For folks (like me) finding this through Google, @Peter and @feoh's answers are the general solution to "How to glob variables in bash script".

    list_of_results=(pattern)
    

    will save existing filenames matching pattern into the array list_of_results. Each element of list_of_results will hold one filename, spaces and all.

    You can access each result as "${list_of_results[<index>]}" for <index> starting from 0. You can get the entire list, properly quoted, as "${list_of_results[@]}".

    0 讨论(0)
  • 2020-12-08 02:39
    ls `echo $dirs` 
    

    works under cygwin.

    0 讨论(0)
  • 2020-12-08 02:44

    I suspect that what you need is an array, but that will restrict you to newer bashes. It is saver than using eval.

    dirs=( /"content with spaces"/{dev01,dev02} )
    
    dirs=( /content/{dev01,dev02} )
    ls -l "${dirs[@]}"
    

    /content/{dev01,dev02}
    

    will expand to:

    "/content/dev01" "/content/dev02"
    

    The existence of those directories is irrelevant to the expansion.

    It becomes unpredictable when you assign a variable to a brace expansion.

    dirs=/content/{dev01,dev02}
    

    may turn into

    "/content/dev01"
    

    or

    "/content/dev01 /content/dev02"
    

    or

    "/content/dev01" "/content/dev02"
    

    or

    "/content/{dev01,dev02}"
    

    If you quote the braces in any way they will not expand, so the result will contain the braces and be mostly meaningless.

    0 讨论(0)
提交回复
热议问题