0

I have an interesting problem that I can't seem to find the answer for. I am creating a simple app that will help my dev department auto launch docker containers with NginX and config files. My problem is, for some reason I can't get the bash script to store the name of a folder, while scanning the directory. Here is an extremely simple example of what I am talking about....

#!/bin/bash

getFolder() {
    local __myResultFolder=$1
    local folder
    for d in */ ; do
        $folder=$d
    done
    __myResultFolder=$folder
    return $folder
}

getFolder FOLDER

echo "Using folder: $FOLDER"

I then save that simple script as folder_test.sh and put it in a folder where there is only one folder, change owner to me, and give it correct permissions. However, when I run the script I keep getting the error...

./folder_test.sh: 8 ./folder_test.sh: =test_folder/: not found

I have tried putting the $folder=$d part in different types of quotes, but nothing works. I have tried $folder="'"$d"'", $folder=`$d`, $folder="$d" but none of it works. Driving me insane, any help would be greatly appreciated. Thank you.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Neglected Sanity
  • 1,770
  • 6
  • 23
  • 46

2 Answers2

2

If you want to save your result into a named variable, what you're doing is called "indirect assignment"; it's covered in BashFAQ #6.

One way is the following:

#!/bin/bash
#      ^^^^ not /bin/sh; bash is needed for printf -v

getFolder() {
  local __myResultFolder=$1
  local folder d
  for d in */ ; do
    folder=$d
  done
  printf -v "$__myResultFolder" %s "$folder"
}

getFolder folderName
echo "$folderName"

Other approaches include:

  • Using read:

    IFS= read -r -d '' "$__myResultFolder" < <(printf '%s\0' "$folder")
    
  • Using eval (very, very carefully):

    # note \$folder -- we're only trusting the destination variable name
    # ...not trusting the content.
    eval "$__myResultFolder=\$folder"
    
  • Using namevars (only if using new versions of bash):

    getFolder() {
      local -n __myResultFolder=$1
      # ...your other logic here...
      __myResultFolder=$folder
    }
    
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
1

The culprit is the line

$folder=$d

which is treating the folder names to stored with a = sign before and tried to expand it in that name i.e. literally treats the name =test_folder/ as an executable to be run under shell but does not find a file of that name. Change it to

folder=$d

Also, bash functions' return value is only restricted to integer types and you cannot send a string to the calling function. If you wanted to send a non-zero return code to the calling function on $folder being empty you could add a line

if [ -z "$folder" ]; then return 1; else return 0; fi

(or) if you want to return a string value from the function, do not use return, just do echo of the name and use command-substitution with the function name, i.e.

getFolder() {
    local __myResultFolder=$1
    local folder
    for d in */ ; do
        folder=$d
    done
    __myResultFolder=$folder
    echo "$folder"
}

folderName=$(getFolder FOLDER)
echo "$folderName"
Inian
  • 80,270
  • 14
  • 142
  • 161
  • The "just don't do indirect assignment" approach has some merit -- particularly with respect to portability and simplicity -- but sometimes the limitations around performance, scoping and variable persistence (consider the case where you want to maintain a cache for an interim lookup -- anything cached in a subshell is lost on function exit) make it unworkable. – Charles Duffy Jan 03 '17 at 19:12