False positive grep?

Heyas

While I was working a bit on pick , my select emulator, I started to get an endless loop...

I could point it down to my 'arrow-keys catch code':

# Check for arrow keys
builtin echo "$NUM" | $GREP -q '^\[\[' && continue

However, while running the code - with regular (expected numeric input)... it becomes this:

++ builtin echo 6
++ grep -q '^\[\['
++ continue

Which definitly is NOT what I had expected as behaviour.
Any ideas why I get this 'false positive'?

Thank you in advance

EDIT:
It is even worse / more weird...

		# Catch invalid inputs
			set -x
			# Keep reading if NUM is empty
			[[ -z "$NUM" ]] && continue
			# Also keep reading if NUM length = 0 ; is this even required?
			[[ ${#NUM} -eq 0 ]] && continue
			# Keep reading if NUM contains letters
			# Using builtin echo for speed and less disk usage
			builtin echo "$NUM" | $GREP -q [a-zA-Z]  && continue	# &2>/dev/zero
			# Check for arrow keys
			builtin echo "$NUM" | $GREP -q '^\[\[' && continue
[[ -z 5 ]]                                                                                              | #
++ [[ 1 -eq 0 ]]

++ builtin echo 5
++ grep -q '[a-zA-Z]'
++ builtin echo 5
++ grep -q '^\[\['
++ continue

Now, I did comment out the the ^[[ -code part, just so it fails at the [a-zA-Z] already....

[[ -z 4 ]]                                                                                              | #
++ [[ 1 -eq 0 ]]

++ builtin echo 4
++ grep -q '[a-zA-Z]'
++ continue

:confused:

The grep args should be quoted so the shell does not try a filename generation.

builtin echo "$NUM" | $GREP -q "[a-zA-Z]"  && continue
4 Likes

Thank you, but nope.

Still fails.
It passes [a-zA-Z] (double & single quotes) just to fail at the '^\[\[' line AFTERwards....
But either way, the "++debug output showed single quotes in the first post, despite not having them.

AHHHHHHHHHHHHHHHHH SCREW IT....
Closed terminal... started a new one and now....

No colors/borders anymore... FFFFFF=white of anger....

Bet the issue was somewhere there (in the env-memory of said now-closed terminal window-tab).....
All my (obviously imagined) fixes.. worthless... once more... again....

I'm back to square one... to fix the display-functions that i THOUGHT were working yesterday evening.. 24 hrs ago... WTF?!?!
No more coding today...

I do remember you being quite concerned with performance in this SWARM stuff and I would have thought the bash =~ operator could be use in place of grep.

$ export NUM='[['
$ time bash -c 'echo "$NUM" | grep -q "^\[\[" && echo yes'
yes

real    0m0.200s
user    0m0.000s
sys     0m0.107s
$ time bash -c '[[ "$NUM" =~ ^\[\[ ]] && echo yes'
yes

real    0m0.099s
user    0m0.015s
sys     0m0.046s

Twice as fast on my system, but your mileage may vary

2 Likes

Sorry for that outbreak...

But it's working now, thank you MIG & Rav, though, mostly because I droped 'those' catches alltogether...
Here's the full working pick :

	pick() { # [-1 -2 -a -m] $LIST or ${ARRAYS[@]}
	# Select an item of a LIST or an ARRAY
	# Returns the value
		#
		# Variables
		#
			local counter=0
			local AUTO=false
			local ROWS="3"
			local as_menu=false
		#
		# Catch arguments
		#
			for opt in "${@}"
			do	if [[ "-" == "${opt:0:1}" ]] 
				then	case "${opt/-}" in
					1|2|3)	ROWS="${opt/-}"
						shift
						;;
					"a")	AUTO=true
						shift
						;;
					"m")	trap "return 130" INT ABRT KILL
						as_menu=true
						shift
						;;
					"-")	wasPipe=true
						;;
					esac
				fi
			done
			# Can not be set earlier because of possible options
			# Which state wether it is 'as menu' or default
			$as_menu && \
				local ARGS=( "${SWARM_MSG_PICK_BACK}" "${@}" ) || \
				local ARGS=("${@}")
		#
		# Pipe handling
		# It's different when working with 'read'
		#
			#wasPipe=false
			#[ -z "$1" ] && \
			#	while IFS= read -r ARG
			#	do	set -- "$@" "$ARG" && wasPipe=true
			#	done
		# Handle auto-pick (only 1 option)
			"$AUTO" && \
				[ "$#" -eq 1 ] && \
				$PRINTF '%s\n' "$ARGS" >&1 && \
				return 4
		# Show the items to pick from
			#set +x
			$as_menu && \
				printlist -n -$ROWS -0 ${ARGS[@]} || \
				printlist -n -$ROWS "${ARGS[@]}"
			#set -x
		# Set dynamic values
			# Amount of arguments
			local pick_count=${#ARGS[@]}
			# Character length of the amount
			local pick_len=${#pick_count}
			#Special handling
			local invalid=true
			local NUM=""
			local POS="$(swarm.print.goto $(( $identRight + 2 )))${SWARM_THEME_DATA[read]} "
			$as_menu && \
				local min=0 || \
				local min=1
		#
		# Visuals
		#
		while $invalid
		do
			# Except the best, prepare for the worst
			#invalid=false
		# Print the input line:
			swarm.print.border
			$PRINTF "$POS      $POS" >&2
		# Read the input 
			builtin read -n $pick_len NUM
		# Catch invalid inputs
			# Keep reading if NUM is empty
			[[ -z "$NUM" ]] && continue
			# Check if NUM is numeric
			if [[ ${#NUM} -ge 0 ]] &2>/dev/zero
			then
				# If it's exactly 0, it's BACK
				[[ ${#NUM} -eq 0 ]] && $ECHO "${ARGS[$NUM]}" && return
				# It's not zero but some other numeric input
				
				# Keep reading if it is not greater than 'min'-imum
				[[ ${NUM} -ge $min ]] &2>/dev/zero || continue
				# Keep reading if it is greater than pick_count
				[[ $NUM -gt $pick_count ]] && continue
				
				# Exit the loop
				invalid=false
			else
				# It's not a number, catch other cases
				continue
			# Actualy, all checks below are (can be) left out....	
				# Keep reading if NUM contains letters
				# Using builtin echo for speed and less disk usage
				builtin echo "$NUM" | $GREP -E -q "[a-zA-Z]"  && continue	# &2>/dev/zero
				# Check for arrow keys
				#builtin echo "$NUM" | $GREP -E -q "^\[\[" && continue
				[[ "$NUM" =~ '^[[' ]] && continue
				# Keep reading if NUM is longer than $pick_len
				# ?? This SHOULD catch arrow-keys in most real usage cases
				[[ ${#NUM} -gt ${pick_len} ]] &2>/dev/zero && continue
			fi
		done
		# Make 'nice to have' line break when read automatically stops reading
		if [ "${#NUM}" -eq "${#len}" ] 
		then	# Only print newline character if the entered number as the longest number
			# But not sub zero
			[ "${NUM}" -ne -1 ] && $PRINTF "\n" >&2
		else	# Since arrays are 0 indexed, 10 becomes 9 and need special treatment
			[ "${NUM}" -eq 9 ] && $PRINTF "\n" >&2
		fi
		$as_menu || NUM=$(( $NUM - 1))
		
		# Prepare output
		$ECHO "${ARGS[$NUM]}"
		unset opt
	}
2 Likes

Consequently you should replace the other grep -E -q with a [[ =~ ]] .

And &2>/dev/zero looks odd. Perhaps you mean 2>/dev/null but this is not appropriate after a [[ ]] compound.

Good morning MIG :slight_smile:

Yes, I'm always getting confused whether to use /dev/null or /dev/zero, because most of the *nix flavors I use, have both.

if [[ ${#NUM} -ge 0 ]] &2>/dev/null

Yes, this might be unususal, but it helps to avoid parsing errors -> well the visual breakup <- when 'catching' arrow keys (NOT specificly).

Are you refering to the other '^[[' line just above - which is commented out, or to the '[a-zA-Z]' grep to be changed to ~= ?
But basicly, neither of those lines are 'now' executed, because it's 'all' left out anyway - to my understanding - the only reason it's still there, is because I just had it rewritten it compared to the initial post (before sleeping).

			else
				# It's not a number, catch other cases
				continue
			# Actualy, all checks below are (can be) left out....	

Or am I missing a point of yours?
Thank you.

&2>/dev/null is still odd, the & is too many. The & before a descriptor number is needed on the RHS only, to distinguish it from a file name.
And, the only errors that a [[ ]] can produce are "syntax error", "not an integer", "division by zero". You want to see them!
If you want to supress an error from an embedded sub shell expression than redirect it within the sub shell.

In general, only suppress error messages when it makes sense - they help you!

And yes, I meant the

builtin echo "$NUM" | $GREP -E -q "[a-zA-Z]"  && continue

that should become

[[ "$NUM" =~ [a-zA-Z] ]] && continue
2 Likes

Thank you, I'll try to keep that present (2 & null) after reviewing current code.
What is this RHS you are refering to please?

Uhm, not really on the possible error topic - as I experienced it differently.
....
Phew... i still had that in the terminal so I could scroll to it...

# | 45) swarm.util.mkdir                                                                     46) swarm.util.which | #
# | > ^[[A/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 538: [[: e[: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"e[\").
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 561: [: e[: Ganzzahliger Ausdruck erwartet.
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 568: e[: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"e[\").
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 536: [[: e[: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"e[\").

This is with code of the 'initial' post/s ; where the 'catch' was different from the code we're talking about now (recent post with code).
This 'symbol' cannot be compared to a number, thus creating an 'expected' error message, which I wanted to get rid of -> as it breaks the visual experience.

Could you advice a better handling for this situation?
-> Catching arrow keys without showing the enduser an error message? <-

Err...
Why do I keep forgetting to post the other half?

Even with the suggested change by Ravinder, I keep getting these error messages.

# | 45) swarm.util.mkdir                                                                     46) swarm.util.which | #
# | > ^[[A++ [[ e[ =~ ^\[\[ ]]                                                                                    | #
++ set +x
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 540: [[: e[: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"e[\").
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 538: [[: e[: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"e[\").
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 563: [: e[: Ganzzahliger Ausdruck erwartet.
/home/sea/prjs/SWARM/data/libs/util.enduser: Zeile 570: e[: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"e[\").

Where I would have expected a continue before the ++set +x ...

My point beeing, sadly, that even with the suggest speed-increase changes, it fails with an error message to the user.

EDIT:
And you were right... (I know wasnt what you wanted to point out):

if [[ ${#NUM} -ge 0 ]] >/dev/null

Is what now solves my expections.

I really wish that those checks would have work/ed out as expected/anticpated, but none did, nor does.
So, I'm left with what is working (gives the expected result), allthough not nice.

EDIT2:
Nevermind.. I tested wrong (forgot to actualy press an arrow key on the X'th 'last' run)...
It's still all messed up when pressing an arrow key.... :frowning:

That explains it; and your photo shows a non-ascii character.
It's not sufficient to sort out [a-zA-Z].

With an ERE you can ensure the input is a number:

[[ $NUM =~ ^[0-9]+$ ]] || continue
echo "$NUM is a positive integer"
[[ $NUM =~ ^-?[0-9]+$ ]] || continue
echo "$NUM is an integer"

RHS == right hand side

3 Likes

Thank you very much!
This works perfectly! :slight_smile:

Yes, I'm always getting confused whether to use /dev/null or /dev/zero, because most of the *nix flavors I use, have both.

As well they should, but they're different. /dev/zero produces zeroes. If you don't need a bunch of zeroes - and who does? - don't use it. null is an esoteric term for nothing, so when you need a device which does nothing - which, despite all odds, is constantly useful - that's null. :slight_smile:

1 Like