bashpathconcatenationconfigreadlink

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


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.


Solution

  • 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)