Assigning dynamic bash variable names using a for loop seq

后端 未结 3 1056
离开以前
离开以前 2020-12-19 18:56

So I\'m trying to do something, not sure if it\'s possible. I have the following code:

for i in {0..5}; do
    if [[ -f ./user$i ]]; then
        group$i=$(g         


        
相关标签:
3条回答
  • 2020-12-19 19:16

    Use declare group$i=... instead of just group$i=...

    0 讨论(0)
  • 2020-12-19 19:22

    Try to use the export or declare function like this

    for i in {0..5}; do
        if [[ -f ./user$i ]]; then
            export group$i=$(grep -w "group" ......
    

    with declare

    for i in {0..5}; do
        if [[ -f ./user$i ]]; then
            declare group$i=$(grep -w "group" ......
    

    where export makes the value available to sub-processes, and declare just available within the same script.

    0 讨论(0)
  • 2020-12-19 19:35

    Kurt Stutsman provides the right pointer in a comment on the question: use Bash arrays to solve your problem.

    Here's a simplified example:

    groups=() # declare an empty array; same as: declare -a groups
    for i in {0..5}; do
      groups[i]="group $i"  # dynamically create element with index $i
    done
    
    # Print the resulting array's elements.
    printf '%s\n' "${groups[@]}"
    

    See the bottom of this answer for other ways to enumerate the elements of array ${groups[@]}.

    • bash arrays can be dynamically expanded (and can even be sparse - element indices need not be contiguous)

      • Hence, simply assigning to element $i works, without prior sizing of the array.
    • Note how $i need not be prefixed with $ in the array subscript, because array subscripts are evaluated in an arithmetic context (the same context in which $(( ... )) expressions are evaluated).


    As for what you did wrong:

    group$i=...
    

    is not recognized as a variable assignment by Bash, because - taken literally - group$i is not a valid identifier (variable name).

    Because it isn't, Bash continues to parse until the next shell metacharacter is found, and then interprets the resulting word as a command to execute, which in your case resulted in error message group0=j: command not found.


    If, for some reason, you don't want to use arrays to avoid this problem entirely, you can work around the problem:

    By involving a variable-declaring builtin [command] such as declare, local, or export, you force Bash to perform expansions first, which expands group$i to a valid variable name before passing it to the builtin.

    • user2683246's answer demonstrates the next best approach by using declare (or, if local variables inside a function are desired, local) to create the variables.

    • Soren's answer uses export, but that is only advisable if you want to create environment variables visible to child processes rather than mere shell variables.

    Caveat: With this technique, be sure to double-quote the RHS in order to capture the full value; to illustrate:

     i=0; declare v$i=$(echo 'hi, there'); echo "$v0" # !! WRONG -> 'hi,': only UP TO 1ST SPACE
    
     i=0; declare v$i="$(echo 'hi, there')"; echo "$v0" # OK -> 'hi, there'
    

    Other ways to enumerate the groups array created above:

    # Enumerate array elements directly.
    for element in "${groups[@]}"; do
      echo "$element"
    done
    
    # Enumerate array elements by index.
    for (( i = 0; i < ${#groups[@]}; i++ )); do
      echo "#$i: ${groups[i]}"
    done
    
    0 讨论(0)
提交回复
热议问题