Reputation: 3600
I have a variable which contain for example ['Cars', 'House', 'Bike']
. I want to be able to search for an exact match with values contained in the string.
Exemple:
Cars
exist in the variable. It should return true
.Car
exist in the variable. It should return false
.What I tried :
#!/bin/bash
search="Car"
arr="['Cars', 'House', 'Bike']"
if [[ $search =~ .*"$arr".* ]]; then
echo "true"
else
echo "false"
fi
# Output true | Expected false
Another script :
#!/bin/bash
search="Cars"
arr="['Cars', 'House', 'Bike']"
check=0
grep -o "'[^']*'" <<<"$arr" | sed "s/'//g" |
while read -r elem; do
if [ "$search" == "$elem" ]; then
check=1
fi
done
if [ "$check" == 1 ]; then
echo "true"
else
echo "false"
fi
# Output false | Expected true
Upvotes: 1
Views: 704
Reputation: 1025
If you don't want to use anything but bash, you can use bash arrays.
There are pros and cons, as always.
One of the pro is that you don't have to install any third program in order to make it work and it will run also in other shells like cygwin
.
I wrote a piece of code for example:
#!/bin/bash
search="Car"
arr="['Cars', 'House', 'Bike']"
arr="$(printf "%s" "${arr}" | sed -e "s/,//g" -e "s/^\[/(/" -e "s/\]$/)/")"
eval arr="${arr}"
for var in ${arr[@]}; do
if [ "${var}" = "${search}" ]; then
printf "%s\n" "true"
exit
fi
done
printf "%s\n" "false"
This code anyway takes for granted some things and have some cons.
For example, it takes for granted that all your input is like the sample, without any "," inside the actual variables.
Upvotes: 0
Reputation: 8184
There are several problems with the regular expression match in the first Bash example code in the question. The biggest problem is that $search
and $arr
are on the wrong sides of the match operator. The lack of (quoted) single quotes in the pattern is also a serious problem. Regular expression matching is overkill for this anyway. The simpler "glob" pattern matching is sufficient. Try this:
#!/bin/bash
search=Car
arr="['Cars', 'House', 'Bike']"
if [[ $arr == *"'$search'"* ]]; then
echo true
else
echo false
fi
See glob - Greg's Wiki for information about glob patterns.
Upvotes: 1
Reputation: 247042
With a ruby one-liner:
$ json_arr="['Cars', 'House', 'Bike']"
$ ruby -rjson -e '
data = JSON.parse(ARGV.shift)
puts data.include?(ARGV.shift)
' "${json_arr//\'/\"}" Cars
true
$ ruby -rjson -e '
data = JSON.parse(ARGV.shift)
puts data.include?(ARGV.shift)
' "${json_arr//\'/\"}" Donkey
false
Note that JSON strings must use double quotes (https://json.org/), so I'm using the shell's parameter substitution to translate single quotes to double quotes.
Upvotes: 0
Reputation: 3600
I found a way to modify the global variable in the loop. Thank you all for suggestion. Here is the script :
#!/bin/bash
search="Cars"
arr="['Cars', 'House', 'Bike']"
check=0
for elem in $(grep -o "'[^']*'" <<<"$arr" | sed "s/'//g")
do
if [ "$search" == "$elem" ]; then
check=1
fi
done
if [ "$check" == 1 ]; then
echo "true"
else
echo "false"
fi
# Output true | Expected true
Upvotes: 0
Reputation: 8204
Some answers about how to do this in some other language. I think you want to know why your bash script isn't working.
The reason is fundamentally that when you are setting check=1
inside the if statement, you're in a different shell, so it doesn't affect the check
that's defined in the outer script. It's a different shell because you're piping input into the while from another command.
A few ways to make this work:
Send the output of the grep
pipeline to a temporary file, then execute the while loop in your main shell script and read the input from the file.
You could also return whether or not you found the string you're looking for via the exit code and preserve it in check
using the $?
variable that stores the exit code of the last process.
grep -o "'[^']*'" <<<"$arr" | sed "s/'//g" |
while read -r elem; do
if [ "$search" = "$elem" ]; then
exit 1
fi
done
check=$?
Since using the exit code in your while loop basically makes it into a poor version of fgrep
, you could just use fgrep
and check the exit code.
Upvotes: 1
Reputation: 198436
In Python:
search="Car"
arr="['Cars', 'House', 'Bike']"
import ast
output = search in ast.literal_eval(arr)
As a one-liner in a shell script that outputs True
or False
:
python -c 'import sys; import ast; print(sys.argv[1] in ast.literal_eval(sys.argv[2]))' "$search" "$arr"
As a one-liner in a shell script that returns 0 (okay) or -1 (not okay) exit status, as is usual in shell:
python -c 'import sys; import ast; sys.exit(0 if sys.argv[1] in ast.literal_eval(sys.argv[2]) else -1)' "$search" "$arr"
Upvotes: 1