I have the following script for creating projects: clearversion=0.0.2echo Project creatorecho ---------------# ask user to specify a directory (could start with spelled-out home directory)directoryName=# Input must meet the following criteria: # 1.) No spaces at all in the directory path# 2.) some characters must be enteredwhile [[ ${#directoryName} -eq 0 || $directoryName == * * ]]        do                echo -e \nEnter the full directory of the project (no spaces):                read directoryName        doneecho You entered: $directoryName# uate directoryName so that the rest of the code can understand it# create directory if it does not existeval mkdir $directoryName# if successfulif [ $? -eq 0 ]then        # call executable in /home/miwarren/CPPFileCreator to create a main.cpp file to put in the folder        $HOME/CPPFileCreator/a.out $directoryName        # copy a run.sh file into the folder, too...        eval cp $HOME/CPPFileCreator/run.sh $directoryName/run.sh        # you might want to put a fileCreator.sh in the folder as well        eval cp $HOME/fileCreator.sh $directoryName/fileCreator.shfiI make sure to strip out any spaces (assumed that every unsafe string has at least a space in it, because injection-style attack). I want users to not have to spell out path parts when there exist variables for it (for example, $HOME for the home directory). Am I still good to use eval here, and if not, what to do instead?
Eval for filenames, evil?
bash;shell script
I want users to not have to spell out path parts when there exist  variables for it (for example, $HOME for the home directory).That can be done without eval:$ s='$HOME/.config'$ s=${s//\$HOME/$HOME}$ echo $s/home/john1024/.configThis has some limitations.  For one, if both HOMES and HOME are names of variables that you want to substitute, then, to avoid false matches, HOMES must be substituted before HOME.Applying substitutions for all exported variablesUsing bash:while IFS== read -r name valdo   s=${s//\$$name/$val}done < <(printenv)For example:$ export A=alpha; export B=beta$ s='$HOME/$A/$B'$ while IFS== read -r name val; do s=${s//\$$name/$val}; done < <(printenv)$ echo $s/home/john1024/alpha/betaBecause this approach doesn't sort the variable names by length, it has the variable overlap issue mentioned above.We can fix that by sorting the variable names according to length:while IFS== read -r n name valdo   s=${s//\$$name/$val}done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,,key); printf %s=%s\n,length(key),$0}' | sort -rnt=)If the user enters a variable name that does not exist but the initial characters match some shorter name, the shorter name will be substituted.  If this matters, we can avoid it by requiring the user to use brace-notation for this variables with this code:while IFS== read -r n name valdo   s=${s//\$\{$name\}/$val}done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,,key); printf %s=%s\n,length(key),$0}' | sort -rnt=)As an example:$ s='${HOME}/${A}/${B}'$ while IFS== read -r n name val; do s=${s//\$\{$name\}/$val}; done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,,key); printf %s=%s\n,length(key),$0}' | sort -rnt=)$ echo $s/home/john1024/alpha/beta