Difficulty using readlink in bash with mix of variables and string to return absolute paths

1.2k Views Asked by At

I have a config script where users can specify paths as variables in the header section. I want them to be able to use absolute paths, relative paths and variables (because this is actually called from another shell script from where they get the values for the variables). At the end of the script all the paths are written to a text file.

The challenge I have is that variables used within some of the paths can change in the middle of the script. I am having difficulties in re-evaluating the path to get the correct output.

### HEADER SECTION ###
DIR_PATH="$VAR1/STRING1"
InputDir_DEFAULT="$DIR_PATH/Input"
### END HEADER ###

...some code

if [[ some condition ]]; then DIR_PATH="$VAR2/STRING2"; fi

...more code

# $InputDir_DEFAULT needs re-evaluating here
InputDir=$(readlink -m $InputDir_DEFAULT)
echo $InputDir >> $FILE

When I do as above and 'some condition' is met, the return of 'echo' is the absolute path for $VAR1/STRING1/Input, whereas what I want it the abs path for $VAR2/STRING2/Input.

Below is an alternative, where I try to stop InputDir_DEFAULT being evaluated until the end by storing itself as a string.

### HEADER SECTION ###
DIR_PATH="$VAR1/STRING1"
InputDir_DEFAULT='$DIR_PATH/Input' #NOTE: "" marks have changed to ''
### END HEADER ###

if [[ some condition ]]; then DIR_PATH="$VAR2/STRING2"; fi

STRING_TMP=$InputDir_DEFAULT
InputDir=$(readlink -m $STRING_TMP)
echo $InputDir >> $FILE

This time 'echo' returns a mix of the evaluated variables and un-evaluated string: $VAR2/STRING2/$DIR_PATH/Input which (for me) looks like /home/ubuntu/STRING2/$DIR_PATH/Input. It's just the $DIR_PATH/ that shouldn't be there.

This feels like it should be relatively straightforward. I'm hoping I'm on the right path and that it's my use of "" and '' that's at fault. But I've tried lots of variations with no success.

2

There are 2 best solutions below

0
On BEST ANSWER

This is the solution I came to in the end. It's a mix of what was suggested by @ThatsWhatSheCoded and some other stuff to ensure that the user doesn't have to redefine variables anywhere other than in the header.

I expect there's a more elegant way of doing this, but this does work.

### HEADER SECTION ###
DIR_PATH_DEFAULT="$VAR1/STRING1"
InputDir_DEFAULT="$DIR_PATH_DEFAULT/Input"
### END HEADER ###

...some code

if [[ some condition ]]; then DIR_PATH="$VAR2/STRING2"; fi

### Checks whether $DIR_PATH_DEFAULT is used in any variables.
### If so and $DIR_PATH is different, will replace string.
### This will be done for all variables in a list.
if [[ ! "$DIR_PATH_DEFAULT" =~ "$DIR_PATH" ]]; then
    for i in ${!var[@]}; do
        var_def_val=${var[i]}_DEFAULT
        STRING_TMP=${!var_def_val}
        var_def=${var[$i]}_DEFAULT
        if [[ $STRING_TMP == *"$DIR_PATH_DEFAULT"* ]] && [[ ! $var_def == "DIR_PATH_DEFAULT" ]]; then
            STRING_TMP="${STRING_TMP/$DIR_PATH_DEFAULT/$DIR_PATH}"
            eval "${var_def}=$STRING_TMP"
        fi
    done
fi

...more code

InputDir=$(readlink -m $InputDir_DEFAULT)
1
On

When you initially set InputDir_DEFAULT, it is taking the currently set value for ${DIR_PATH}; even if you update ${DIR_PATH} later on, InputDir_DEFAULT will remain what it was set to earlier. To resolve this in your current script, you could set InputDir_DEFAULT again inside the if statement:

InputDir_DEFAULT=${DIR_PATH}/Input

Additionally, in your second attempt the single quoted value setting translates to the literal string value and does not expand to the variable's value:

InputDir_DEFAULT='$DIR_PATH/Input'

I would recommend referring to the "Quoting" section in the GNU Bash manual.