6

I am reading a csv file in bash script as follows:

resource='/data/bscs/'
while IFS='|'read seqid fname fpath 
do
    echo "FILENO:         $seqid"
    echo "FILENAME:       $fname"
    echo "FILE_PATH:    $fpath"                    
done < "report.csv"

My csv file has following values :

3|sample1.txt|$resource/operation/

I want the $resource to expand inside $fname. Instead, I am getting this output:

FILENO:         3
FILENAME:       sample1.txt
SOURCE PATH:    $resource/operation

I have tried the following:

"${fpath}" $(echo $fpath)

How can I achieve this?

1
  • Try to add after do eval fpath=$fpath or exchange echo "FILE_PATH: $fpath" by echo "FILE_PATH: ${fpath/\$resource/$resource}"
    – Costas
    Apr 2, 2015 at 14:24

4 Answers 4

6

You can use eval, but the next maintainer will curse your name. Have you tried just appending the variable when using the parsed data, or expanding the variable when creating the data?

If the file is created that way, can't you just use some [redacted] techniques to convince the originator to change their wicked ways?

If change is literally not possible, then you must have control over which variables are possible. Otherwise your script is vulnerable to all sorts of injection attacks, such as inputs like 3|sample1.txt|$(rm --arr --eff /)/operation/. Since you obviously have that under control, you can do some literal replacements of variables with their values on a case by case basis:

IFS='/' read -a pathnames <<< "$fpath"
for pathname in "${pathnames[@]}"
do
    if [ "${pathname::1}" = '$' ]
    then
        variable_name="${pathname:1}"
        printf '%s' "${!variable_name}"
    else
        printf '%s' "$pathname"
    fi
done

With some additional boilerplate to add slashes between pathnames.

2
  • I cannot expand variable in file because the file does not belong to me. The file is created that way.
    – Menon
    Apr 2, 2015 at 14:30
  • @I0b0, eval works for me and has not caused any problems till now. I think I will stick to that for the meantime. Thanks for helping.
    – Menon
    Apr 3, 2015 at 8:31
4

You can also use indirect variable expansion

$fpath=`echo $resource/operation`
echo ${!fpath}

This will expand the value of resource inside fpath.

2
  • I cannot do this because there are other variables in file, so I will have to expand all of them. Besides, I dont know the input values.
    – Menon
    Apr 2, 2015 at 14:37
  • @Menon you've shot down all the ideas presented above. Could you probably add more detail to your question on what do you mean by other variables in file? Some examples perhaps?
    – rahul
    Apr 2, 2015 at 14:44
3

Variable expansion happens just once and isn't recursive.

You can expand the value yourself:

resource=/data/bscs
fpath='$resource/operation'
echo ${fpath/'$resource'/$resource}

Note that this is much safer than eval, because all the possible variables to substitute must be listed in the code.

1
  • 1
    Unfortunately, I have to read values from file and there are different variables in file and it is not possible for me to expand all of them this way.
    – Menon
    Apr 2, 2015 at 14:28
0

I do not know why people hate on eval. When used right does not cause problems.

Simplest solution would be:

    read -p "File Path: " FILE_PATH
    FILE_PATH=$(eval echo $FILE_PATH)

Edit: (explanation) Simply put, if you know your data will be OS PATH, just make sure it is expanded from variables before using it. Do that by evaluating all possible values in it, this is what eval is for. Using it before every command is just a nightmare - use it on your variables that you are using in command.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.