Problem with eval a generated and interpreted variable name and its value

Heya

I have modified $HOME/.config/user-dirs.dirs to my like and the variables are properly 'structured' (XDG_XY_DIR="$HOME/YZ").
Now since i wrote a script to do that part, i currently stuck at the part to create a new .gtk-bookmarks file.

Regarding code snippet: (bold part beeing troublesome)

#
#	Variables for the script internaly
#
	CONFIG=$HOME/.config/user-dirs.dirs
	CONFIG_BAK=$CONFIG-$(date +'%F').bak
	BOOKMARK=$HOME/.gtk-bookmarks
	BOOKMARK_BAK=$HOME/.gtk-bookmarks-$(date +'%F').bak
	IFS_ORG="$IFS"
	IFS="="
# .... some other code ...
#
#	Prepare bookmarks
#
	source "$CONFIG"
	while read var val;do
		if [ "X" = "${var:0:1}" ] && [ "\"" = "${val:0:1}" ]
		then 	lbl="${var/XDG_/}"
			lbl="${lbl/_DIR/}"
			lbl="${lbl,,}"
			lbl="${lbl^}"
			path="${val/\"/}"	# Why do i need to call this twice?
			path="${path/\"/}"	# Why do i need to call this twice?
			RAW="\$$var"		# Line 100
			echo "file://"$RAW" ${lbl}-raw" >> "$BOOKMARK"
			echo "file://"$(echo $RAW)" ${lbl}-raw2" >> "$BOOKMARK"
			echo "file://"$(echo $(eval $RAW))" ${lbl}-raw3" >> "$BOOKMARK"
			echo "file://"$(eval $(echo $RAW))" ${lbl}-raw4" >> "$BOOKMARK"
			XDG="$(eval $(echo $RAW))" 	&& 	echo "file://"$XDG" ${lbl}" >> "$BOOKMARK"
			XDG2="$(echo $(eval \$$var))" 	&& 	echo "file://$XDG2 ${lbl}2" >> "$BOOKMARK"
			XDG3="$(echo $(eval $(echo \$$var)))" && echo "file://$XDG3 ${lbl}3" >> "$BOOKMARK"
			XDG4="$(eval \$$var)" 		&& 	echo "file://$XDG4 ${lbl}4" >> "$BOOKMARK"
			echo $? "Added $path as $lbl"	# Line 109
		fi
	done < "$CONFIG"
	IFS="$IFS_ORG"

I somehow remember (at least i think it did) that eval was the right tool to accomplish this.
Sadly, the builtin_bash manpage dont help me further:

  eval [arg ...]
              The args are read and concatenated together into a single command.
              This command is then read and executed by the shell, and its  exit
              status is returned as the value of eval.  If there are no args, or
              only null arguments, eval returns 0.

Now the .gtk-bookmarks look like:

file://$XDG_DESKTOP_DIR Desktop-raw
file://$XDG_DESKTOP_DIR Desktop-raw2
file:// Desktop-raw3
file:// Desktop-raw4
file:// Desktop2
file:// Desktop3
file://$XDG_DOCUMENTS_DIR Documents-raw
file://$XDG_DOCUMENTS_DIR Documents-raw2
file:// Documents-raw3
file:// Documents-raw4
file:// Documents2
file:// Documents3
...

As the script reports:

Save settings
Backing up /home/sea/.config/user-dirs.dirs 
0 Created backup (/home/sea/.config/user-dirs.dirs-2014-04-16.bak)
Backing up /home/sea/.gtk-bookmarks-2014-04-16.bak... 
0 Created backup (/home/sea/.gtk-bookmarks-2014-04-16.bak)
Writing /home/sea/.config/user-dirs.dirs... 
0 Written /home/sea/.config/user-dirs.dirs
/home/sea/exported-tweak_folders.sh: line 103: /home/sea/notepad: Is a directory
/home/sea/exported-tweak_folders.sh: line 104: /home/sea/notepad: Is a directory
/home/sea/exported-tweak_folders.sh: line 105: /home/sea/notepad: Is a directory
/home/sea/exported-tweak_folders.sh: line 106: /home/sea/notepad: Is a directory
/home/sea/exported-tweak_folders.sh: line 107: /home/sea/notepad: Is a directory
/home/sea/exported-tweak_folders.sh: line 108: /home/sea/notepad: Is a directory
126 Added $HOME/notepad as Desktop
/home/sea/exported-tweak_folders.sh: line 103: /home/sea/priv/docs: Is a directory
/home/sea/exported-tweak_folders.sh: line 104: /home/sea/priv/docs: Is a directory
/home/sea/exported-tweak_folders.sh: line 105: /home/sea/priv/docs: Is a directory
/home/sea/exported-tweak_folders.sh: line 106: /home/sea/priv/docs: Is a directory
/home/sea/exported-tweak_folders.sh: line 107: /home/sea/priv/docs: Is a directory
/home/sea/exported-tweak_folders.sh: line 108: /home/sea/priv/docs: Is a directory
126 Added $HOME/priv/docs as Documents

Where's my problem handling 'eval', any ideas?
Thank you in advance.
Regards
sea

EDIT, evnironement is:

uname -r;$SHELL --version
3.13.9-200.fc20.x86_64
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu) Copyright (C) 2011 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.

eval is almost never the answer. The same usually goes for dynamic variable names. If you find yourself using either, you've taken a wrong turn somewhere.

You can use a here-document to safely turn your variables into strings. Much better than eval.

echo "cat <<EOF" >> /tmp/$$
# copy into /tmp/$$ removing backticks and () to prevent accidental/malicious execution of commands
tr -d '`()' < configfile >> $/tmp/$$
echo "EOF" >> /tmp/$$

. /tmp/$$ > /tmp/$$-1

rm /tmp/$$

It works by creating a file like this:

cat <<EOF
bookmark
bookmark
bookmark
EOF

...and running it in your shell to create another file.

/tmp/$$-1 should now contain the same text as your GTK file with $VARIABLE names substituted.

TIP: You can do ${VARNAME}stuff instead of $VARNAME stuff in your config file. The shell will look for the { } so you won't need spaces to separate them out.

1 Like

This worked, thank you :slight_smile:

BOOKMARK=$HOME/.gtk-bookmarks
CONFIG=$HOME/.config/user-dirs.dirs
DEST=$HOME/gtk-bookmarks.txt
. $CONFIG
echo "cat <<EOF" >> /tmp/$$
# copy into /tmp/$$ removing backticks and () to prevent accidental/malicious execution of commands
tr -d '`()' < $BOOKMARK >> /tmp/$$
echo "EOF" >> /tmp/$$

. /tmp/$$ > $DEST

rm /tmp/$$
cat $DEST