I have a file with this structure:


and here is my program:



cat input.txt | while read col1 col2 col3; do
    echo ${col1}
    echo ${col2}
    echo ${col3}
    echo "********************************"

I want to insert ${token} while reading file. because token is a dynamic word and I can not change it inside the file every time. So I add ${token} to the file once. But the output of program is:


Why this is happening? ma${token}jid should be expand like this: echo ma${token}jid, then 12345678 should be inserted.


The value of col1 is the 13-character string ma${token}jid. When you write echo ${col1} with no quotes, the shell replaces ${col1} by the value of the variable, then performs word splitting (i.e. breaking up the value into separate words at $IFS characters) and filename generation (i.e. globbing). Variable values are not recursively expanded using shell syntax. If you use double quotes around variable substitution (which you should do unless you have a good reason not to), "$col1" straightforwardly expands to the value of col1.

If your strings are tame enough (i.e. contain no shell special characters, apart from the ${token} that you want to substitute), then you can construct a string from $col1 that you evaluate as a shell snippet. In your example, the following line would print ma12345678jid:

eval "echo $col1"

Alternatively, replace the marker ${token} by the desired value. You can do it with a string substitution in bash:

while read -r col1 col2 col3; do
    echo "${col1//'${token}'/$token}"
    echo "${col2}"
    echo "${col3}"
    echo "********************************"
done <input.txt

You can also do it with awk, as a pre- or post-processing step (depending on whether you want to perform the replacement in other columns as well).

<input.txt awk -v repl="$token" '{gsub(/\${token}/, repl); print}' |
while read …

You can perform the replacement with sed, but only if you're sure that none of the characters &\/ and newline appear in the replacement text $token (you can change the separator character from / to something else if there's another character which you're sure doesn't appear in $token).

<input.txt sed -e "s/\\\${token}/$token/" |
while read …

Variables when echoed are not subject to variable expansion. Prepend eval to echo. This might work for simple cases, but can break if your strings contain | or quotes. Or, just do the substitution:

echo ${col1/'${token}'/$token}

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.