[BASH] Read value of variable, but not comment on the same line

Heyas

So while i'm trying to increase security/usability of my TUI commands, i'm currently at tui-conf-get .
There was also a bug, i wanted to fix, but sadly that bugfix is more insecure - but twice as fast as my current buggy method.

I've added a getopts toggle, '-s' to toggle beSecure , meaning to use either source or awk .

Anyway, here's the code after getopts:

	CONFFILE="$1"
	VARNAME="$2"
	
	# If VARNAME starts with Pass|password|pw, do not source the conf file but use awk
	case "$VARNAME" in
	[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd]|[Pp][Ww]|[Pp][Aa][Ss][Ss])
		beSecure=true
		;;
	esac
	
	[ ! -f "$CONFFILE" ]  && tui-printf -S 1 "$CONFFILE does not exist!" && exit 1
	[ "$CONFFILE" = "${CONFFILE##*/}" ] && CONFFILE="./$CONFFILE"
#
#	Display & Action
#
	if $beSecure
	then	$AWK -F= -v VAR="$VARNAME" '$1 ~ "^[^#]*" VAR "$"{print $2,$3,$4,$5}' "$CONFFILE"|$SED s,'"','',g|head -n1
	else	# This method is about twice the speed of the above
		source "$CONFFILE" && echo "${!VARNAME}"
	fi

To illustrate my bug:

$ echo "variable=value # unwanted comment" > tmp

$ tui-conf-get -s tmp variable
value # unwanted comment

$ tui-conf-get tmp variable
value

Furthermore, if the variable is a list, i'm getting either too few and too many entries with the same awk call on the very only variable read:

echo "list=\"one two three four five six\" # bad comment" >> tmp

bin/tui-conf-get tmp list
one two three four five six

bin/tui-conf-get -s tmp list
one two three four # bad comment  

I'm aware that this is because in awk i only 'use' $2-$5, but then again, why is the comment shown?

My questions:

  1. Is there a way to tell awk to print all columns but not $1?
    I mean, i could add like $2,$3,....$22,$23 -- but what if the list read has 25 or more items?
  2. As i already use sed with the awk command, how would i modify it to remove the quotes, and the hash followed by the comment?

When trying basic regex with sed, i cant get it to work as i expect it to:

$ echo "\"1 2 3 4 5 6\" # comment" | sed s,[\"\#*],,g
1 2 3 4 5 6  comment

Any ideas/advice?
Thank you

Trying to emulate how the shell parses a file is going to be slower - but I guess you are trying to avoid side-effects if beSecure is true.

What functionality is the -s providing?

Also, a suggestion:

	case "$VARNAME" in
	[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd]|[Pp][Ww]|[Pp][Aa][Ss][Ss])
		beSecure=true
		;;
	esac

could be simpified to:

	case "${VARNAME^^*}" in
	PASSWORD|PW|PASS)
		beSecure=true
		;;
	esac

Also, I am curious about this construct:

[ "$CONFFILE" = "${CONFFILE##*/}" ] && CONFFILE="./$CONFFILE"

Why are you prepending ./ ?

1 Like

1) Try sub ($1 FS, "") - should work as long as FS is one single char.
2) Why the sed invocation? And the head -n1 ? Try

awk -F= -v VAR="$VARNAME" '$1 ~ "^[^#]*" VAR "$"{gsub ("#.*$|\"|"$1 FS, ""); print; exit}' 

What exactly do you expect?

1 Like

@ derekludwig

True about that ${VAR^^} , didnt thought of that. :b:
The prefixing of CONFFILE with ./ was required to avoid an error message when it was sourced.

@ RudiC
Since i've gotten either the 'full line' or $2-$5 incl quotes and comments, i wanted to remove the both of them.
Now that is already done with your awk/gsub suggestion. :b:

EDIT: The head was if a variable definition was copied to another line, at some occasions i had 2 output lines.

/solved & improved
Thank you guys

The error message was generated because . was not specified as a directory to search by the PATH environmental variable (and man bash (linux) is not in POSIX mode).

If a variable occurs more than once in a configuration file, wouldn't you want the LAST occurrence?

1 Like

Yikes true, happened because i had commented out the lower line in the testfile.
You asked why i added the ./ :wink:

Currently have:

+ tui $ bin/tui-conf-get -s tmp list
one two three four five six 
+ tui $ bin/tui-conf-get tmp list
1 2 3 4 5 6
+ tui $ cat tmp
variable=value # unwanted commend
list="one two three four five six" # bad comment
list='1 2 3 4 5 6'

I tried to also remove single quotes with the awk, and appended a tail, but it fails:

awk -F= -v VAR="$VARNAME" '$1 ~ "^[^#]*" VAR "$"{gsub ("#.*$|\"|\'|"$1 FS, ""); print}' "$CONFFILE" | tail -n1

But now fails with:

LC_ALL=C bin/tui-conf-get -s tmp list
bin/tui-conf-get: line 136: unexpected EOF while looking for matching `"'
bin/tui-conf-get: line 138: syntax error: unexpected end of file

As soon i remove the \'| it works again like:

LC_ALL=C bin/tui-conf-get -s tmp list
'1 2 3 4 5 6'

Try

awk -F= -v VAR="$VARNAME" '$1 ~ "^[^#]*" VAR "$"{gsub ("#.*$|\"|\047|"$1 FS, ""); RES=$0} END {print RES}' "$CONFFILE"

Awesome, thank you!

I try to avoid these escaped unicodes (or whatever its properly called/label'd), thought, on occasions i had to use it, i used to loop and print all numbers and look 'manualy' for the proper char.

By asking myself 'how did he get that', i got this up:

#!/bin/bash
get_char_num() { # CHAR
# Parses numbers 0 - 999 and checks their result
# for matches against passed CHAR
	PRE=000
	MAX=999
	C=0
	while [ $C -lt $MAX ]
	do	num="${PRE:${#C}}$C"
		[ "$(printf \\$num)" = "$1" ] && \
			echo "\\$num" && \
			break
		((C++))
	done
}
get_char_num "$1"

Or how do you actually get the escape numbers of chars?
hth & ty

man ascii . The 047 is the octal representation of ' . It depends on what tools you're using, which representations those understand. awk does, bash does, look into the respective man page on how to enter string/char constants.

1 Like