[BASH] Getting a semi-tailing backslash when passing (escaped) variables to script

Heyas

Figured me had a 'typo' in tui-conf-set, i went to fix it.
Now, i also figured, it might be nice to have tui-conf-set report (to console, not only exit code) wether it could save the variable to the file or not.

This said, I appended this code: (the tui-title and tui-echo lines are just for debuging)

	# Return true if replaced string was found
	if $GREP $Q "$str_checker" "$CONFFILE"
	then	# Success, visual-report only if verbose is enabled
		tui-title DEBUG-start
		tui-echo "Some value for \"$USER\" to compare in ${PWD} on ${HOSTNAME/*.}"
		tui-echo "$VARNAME"
		tui-echo "$VALUE"
		tui-echo  "\"$str_checker\" as \"$VARNAME\"."
		tui-echo  "\"$VALUE\" as \"$VARNAME\"."
		tui-echo  "$VALUE as $VARNAME."
		tui-title DEBUG-stop
		$beVerbose && tui-status 0 "Saved \"$CONFFILE\""
		exit 0
	else	# It failed, visual-report only if verbose
		$beVerbose && tui-status 1 "Could not write to \"$CONFFILE\""
		exit 1
	fi

Which looks like:

+ bin $ $tcs -v $F/rpm.conf specfile "\\\$prj_path/\\\$prj_name.spec2"
++ echo 'specfile=$prj_path/$prj_name.spec2'
++ sed 's,\$,\\\$,g'
+ SEARCH='specfile=\$prj_path/\$prj_name.spec2'
+ true
+ cmd='sed s,"specfile=\$prj_path/\$prj_name.spec2","specfile="\$prj_path/\$prj_name.spec2"",g -i /home/sea/.config/dev-scripts/prjs/st/rpm.conf'
+ eval 'sed s,"specfile=\$prj_path/\$prj_name.spec2","specfile="\$prj_path/\$prj_name.spec2"",g -i /home/sea/.config/dev-scripts/prjs/st/rpm.conf'
++ sed 's,specfile=$prj_path/$prj_name.spec2,specfile=$prj_path/$prj_name.spec2,g' -i /home/sea/.config/dev-scripts/prjs/st/rpm.conf
++ echo '\$prj_path/\$prj_name.spec2'
++ sed 's,\\\$,$,g'
+ str_checker='$prj_path/$prj_name.spec2'
+ set +x
# |                                           DEBUG-start                                            | #
# | Some value for "sea" to compare in /home/sea/prjs/tui/bin on localdomain                         | #
# | specfile                                                                                         | #
# | \$prj_path/\$prj_name.spec2\                                                                      | #
# | "$prj_path/$prj_name.spec2" as "specfile".\                                                       | #
# | "\$prj_path/\$prj_name.spec2" as "specfile".\                                                     | #
# | \$prj_path/\$prj_name.spec2 as specfile.\                                                         | #
# |                                           DEBUG-stop                                             | #
# | Saved "/home/sea/.config/dev-scripts/prjs/st/rpm.conf"                                  [     ] | #

Which doesnt look 'that' bad, but if you place this output in a terminal window, its quite annoying, please see the attachment.

The script is working, as it actualy saves or changes the passed value of a variable into the file, regardless of plaintext, variables or escaped variables.
Just when i enable verbose mode, to display wether or not the file could be written, ti 'display' fails due to an additional char/symbol i have no idea from where it is comming.

My assumption was, since special chars are passed (\ and $), it also invokes the change from $ to \$ (marked that section bold), and for some reason it appens a \ to the EOL sign $ , but since its the EOL-sign (within a variable), one only char seen is \ .
This theory is destroyed, as that variable is at the end of the output string seen in above text example.

The code below is prior to the finalcheck code from above:

	CONFFILE="$1"
	VARNAME="$2"
	VALUE="$3"
	 
	# File does not exist yet
	if [ ! -f "$CONFFILE" ]
	then	tui-bol-dir "$(dirname $CONFFILE)" || exit 1
                touch "$CONFFILE"
	fi
#
# 	Preformat strings
#
	SEARCH="$( $GREP $OPT -v ^# "$CONFFILE"|$GREP "${VARNAME}=")" #|tr -d '[[:space:]]')"
	SEARCH="$(echo $SEARCH|$SED -e 's/^[[:space:]]*//')"
	
	# Apply options
	$SMALL && VARNAME="${VARNAME,,}" && VALUE="${VALUE,,}"
	$CAPS  && VARNAME="${VARNAME^^}" && VALUE="${VALUE^^}"
	
	# Check for quotes
	printf  "$VALUE"|$GREP $Q [\ \$] && \
		REPLACE="$VARNAME=\"$VALUE\"" || \
		REPLACE="$VARNAME=$VALUE"
	
	# Set proper SED 'divider'
	if echo "$VALUE"|$GREP $Q "$SD"
	then 	# Coma was found
		SD="/"
		printf "$REPLACE"|$GREP "$SD"|$GREP -q '\\' && SD="\\"	# backslash was found
		[ ! "$SD" = "/" ] && \
			printf "$REPLACE"|$GREP ","|$GREP "$SD"|$GREP -q "/" && SD="|"	# Forward slash was found
	fi
	
	# Troubles with VARIABLES due to chars that need to be escaped
        if echo "$REPLACE" | $GREP $Q '[%$+@\]'
	then	hadDollar=true
		str_checker="$(echo $VALUE|$SED s,'\\\$','$',g)"
	else	str_checker="$VALUE"
	fi
#
#	Display & Action
#
	# Save changes, Append or change var=value?
	if ! $GREP "${VARNAME}=" "$CONFFILE" | $GREP $Q -v ^"#"
	then	# Its not there yet, just append it
		if $hadDollar
		then	# It needs special treatement
			echo "$(echo $REPLACE)" >> "$CONFFILE"
		else	# Easy handling
			echo "${REPLACE}" >> "$CONFFILE"
			
		fi
	else	# Its already there, handling according to special chars
		set -x
		SEARCH="$(echo $SEARCH|$SED s,'\$','\\\$',g)"
		if $hadDollar
		then	# It needs special treatement
			cmd="$SED s${SD}\"${SEARCH}\"${SD}\"${REPLACE}\"${SD}g -i $CONFFILE"
			eval "$cmd"
		else	# It is simple to call
			cmd="$SED s${SD}${SEARCH}${SD}${REPLACE}${SD}g -i $CONFFILE"
			$cmd
		fi
		set +x
	fi

Please, any ideas what/why its causing that backslash?
Thank you in advance.

NOTE:
With 'regular' (non-escaped) variables it works (the output between the DEBUG-st*) just fine too.

Not quite understanding your problem, and not knowing the contents of GREP but assuming it's grep , this $GREP $Q [\ \$] yields the error msg grep: [ $]: No such file or directory so it will always execute the FALSE branch of your conditional.
PLUS, you should supply a format string to printf , esp. if VALUE contains special chars.

1 Like

If the $Q is an option, it does work. But you still should quote '[ $]' . The shell will expand that if there is a matching file (ie, you've a file named $ then you no longer will be searching for ' ' and $, but only $).

As for the original problem, if i'm understanding it correctly, it seems to be a bug in tui-echo's ability to interpret backslashes.

1 Like

Added single quotes, and removed the escape chars from that named if block.
And yes, that $Q was/is an option : -q, sry forgot to mention.

During the writing of tui-cat, i've added a code block to tui-printf (the very core display command) which escaped tailing backslashes, you know, to keep them when using tui-cat, and not get them changed to one-liners...
Seems that function also jumped in as soon the strings contained dollars/variables. Though, it seemed to only add a single backslash at the end of the string.
tui-printf:

	# Escape trailing backslash, from whichever argument passed
	# This is supposed to 'keep' artificial linebreaks rather than get them on one line
	echo "$FIRST" | grep -q "\\"$ && \
		FIRST="${FIRST}\\\\"
	echo "$SECOND" | grep -q "\\"$ && \
		SECOND="${SECOND}\\\\"
	echo "$THIRD" | grep -q "\\"$ && \
		THIRD="${THIRD}\\\\"
	
	# Escape '%'
	...
	

So it seems now, that i need something else to preserve articifical linebreaks, but not add unrequred baskslashes to strings with variables...
How to define that $ is supposed to be the line end only, but not a variable indicator at all?
Kind of helpless, as i though the above code whould do so...

Thank you

---------- Post updated at 13:41 ---------- Previous update was at 12:52 ----------

Guess i solved it, at least for this one time test it worked:
Changed it to:

        [ "\\" = "${FIRST:0:(-1)}" ] && \
                FIRST="${FIRST}\\"

Thank you