I want to add the third parameter that will be changing files name from upper to lower OR lower to upper but in this third parameter I want to specify what file's name must be changed? What's wrong with this script? Thank you in advance.
#!/bin/bash
if test "$1" = "lower" && test "$2" = "upper"
then
for file in *; do
if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
mv "$file" "$(echo $file | tr [:lower:] [:upper:])";
fi
fi
done
elif test "$1" = "upper" && test "$2" = "lower"
then
for file in *; do
if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
mv "$file" "$(echo $file | tr [:upper:] [:lower:])";
fi
done
fi
if [ "$1" = "lower" ] && [ "$2" = "upper" ] && [ "$3" = "$file" ];
then
for file in * ; do
if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
mv "$file" "$(echo $file | tr [:lower:] [:upper:])";
fi
done
fi
If I am guessing correctly what you want, try
#!/bin/bash
case $1:$2 in
upper:lower | lower:upper ) ;;
*) echo "Syntax: $0 upper|lower lower|upper files ..." >&2; exit 1;;
esac
from=$1
to=$2
shift; shift
for file; do
mv "$file" "$(echo "$file" | tr "[:$from:]" "[:$to:]")"
done
This has the distinct advantage that it allows more than three arguments, where the first two specify the operation to perform.
Notice also how we take care to always quote strings which contain a file name. See also When to wrap quotes around a shell variable?
The above script should in fact also work with /bin/sh; we do not use any Bash-only features so it should run under any POSIX sh.
However, a much better design would probably be to use an option to decide what mapping to apply, and simply accept a (possibly empty) list of options and a list of file name arguments. Then you can use Bash built-in parameter expansion, too. Case conversion parameter expansion operations are available in Bash 4 only, though.
#!/bin/bash
op=',,'
# XXX FIXME: do proper option parsing
case $1 in -u) op='^^'; shift;; esac
for file; do
eval mv "\$file" "\${file$op}"
done
This converts to lowercase by default, and switches to uppercase instead if you pass in -u before the file names.
In both of these scripts, we use for file as a shorthand for for file in "$#" i.e. we loop over the (remaining) command-line arguments. Perhaps this is the detail you were looking for.
Forgive me if I grossly misunderstand, but I think you may have misunderstood how argument passing works.
The named/numbered arguments represent the values you pass in on the command line in their ordinal positions. Each can theoretically have any value that can by stuck in a string. You don't need a third parameter, just a third value.
Let's try a sample.
#! /bin/env bash
me=${0#*/} # strip the path
use="
$me { upper | lower } file
changes the NAME of the file given to be all upper or all lower case.
"
# check for correct arguments
case $# in
2) : exactly 2 arguments passed - this is correct ;;
*) echo "Incorrect usage - $me requires exactly 2 arguments $use" >&2
exit 1 ;;
esac
declare -l lower action # these variables will downcase anything put in them
declare -u upper # this one will upcase anything in it
declare newname # create a target variable with unspecified case
action="$1" # stored the *lowercased* 1st argument passed as $action
case $action in # passed argument has been lowercased for simpler checking
upper) upper="$2" # store *uppercased* 2nd arg.
newname="$upper" # newname is now uppercase.
;;
lower) lower="$2" # store *lowercased* 2nd arg.
newname="$lower" # newname is now lowercase.
;;
*) echo "Incorrect usage - $me requires 2nd arg to be 'upper' or 'lower' $use" >&2
exit 1 ;;
esac
if [[ -e "$2" ]] # confirm the argument exists
then echo "Renaming $2 -> $newname:"
ls -l "$2"
echo " -> "
mv "$2" "$newname" # rename the file
ls -l "$newname"
else echo "'$2' does not exist. $use" >&2
exit 1
fi
First of all there is indentation problem with this script check first if condition done should be coming before fi
Below is the correct.
if test "$1" = "lower" && test "$2" = "upper"
then
for file in *; do
if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
mv "$file" "$(echo $file | tr [:lower:] [:upper:])";
fi
done
fi
Secondly the question you asked:
#/bin/bash -xe
[ $# -ne 3 ] && echo "Usage: {lower} {upper} {fileName} " && exit 1
if [ "$1" = "lower" ] && [ "$2" = "upper" ] && [ -f "$3" ];
then
mv "$3" "$(echo $3 | tr [:lower:] [:upper:])";
fi
Hope this helps.
I am having trouble with my newbie linux script which needs to count brackets and tell if they are matched.
#!/bin/bash
file="$1"
x="()(((a)(()))"
left=$(grep -o "(" <<<"$x" | wc -l)
rght=$(grep -o ")" <<<"$x" | wc -l)
echo "left = $left right = $rght"
if [ $left -gt $rght ]
then echo "not enough brackets"
elif [ $left -eq $rght ]
then echo "all brackets are fine"
else echo "too many"
fi
the problem here is i can't pass an argument through command line so that grep would work and count the brackets from the file. In the $x place I tried writing $file but it does not work
I am executing the script by writting: ./script.h test1.txt the file test1.txt is on the same folder as script.h
Any help in explaining how the parameter passing works would be great. Or maybe other way to do this script?
The construct <<< is used to transmit "the contents of a variable", It is not applicable to "contents of files". If you execute this snippet, you could see what I mean:
#!/bin/bash
file="()(((a)((a simple test)))"
echo "$( cat <<<"$file" )"
which is also equivalent to just echo "$file". That is, what is being sent to the console are the contents of the variable "file".
To get the "contents of a file" which name is inside a var called "file", then do:
#!/bin/bash
file="test1.txt"
echo "$( cat <"$file" )"
which is exactly equivalent to echo "$( <"$file" )", cat <"$file" or even <"$file" cat
You can use: grep -o "(" <"$file" or <"$file" grep -o "("
But grep could accept a file as a parameter, so this: grep -o "(" "$file" also works.
However, I believe that tr would be a better command, as this: <"$file" tr -cd "(".
It transforms the whole file into a sequence of "(" only, which will need a lot less to be transmitted (passed) to the wc command. Your script would become, then:
#!/bin/bash -
file="$1"
[[ $file ]] || exit 1 # make sure the var "file" is not empty.
[[ -r $file ]] || exit 2 # test if the file "file" exists.
left=$(<"$file" tr -cd "("| wc -c)
rght=$(<"$file" tr -cd ")"| wc -c)
echo "left = $left right = $rght"
# as $left and $rght are strictly numeric values, this integer tests work:
(( $left > $rght )) && echo "not enough right brackets"
(( $left == $rght )) && echo "all brackets are fine"
(( $left < $rght )) && echo "too many right brackets"
# added as per an additional request of the OP.
if [[ $(<"$file" tr -cd "()"|head -c1) = ")" ]]; then
echo "the first character is (incorrectly) a right bracket"
fi
I need some help to write a script for the following scenario.
The requirement is, based on the number of configuration files(*.cfg) inside a given directory, I need load all the configuration file names with out the file extension into an array. If there is only one configuration file in the directory, then array will be assigned the value "" (not the name of the only available configuration file)
I am trying to do this using logical operators. This is what i have tried so far.
[`ls *.cfg |wc -l`] || code_to_initialize_array;
My problem here is that, how do I integrate the case where i have only one configuration file.
Short code:
#!/bin/bash
array=(*.cfg)
array=("${array[#]%.cfg}")
[ ${#array[#]} -eq 1 ] && array=""
#!/bin/bash
config=(*.cfg) #glob instead ls usage
num=${#config[#]}
case $num in
0)
echo "No config file"
;;
1)
echo "Only one config file"
;;
*)
code_to_initialize_array
;;
esac
You can have this example script for your requirement. It's detailed and variable names are long but you could have your own customizations. Using readarray is safer than A=($(...)) since it doesn't depend on IFS and is not subject to pathname expansion.
#!/bin/bash
DIR=/path/to/somewhere
readarray -t FILES < <(compgen -G "${DIR%/}/*.cfg") ## Store matches to array.
FILES_COUNT=${#FILES[#]} ## Match count.
FILES_NAMES=("${FILES[#]##*/}") ## No directory parts.
FILES_NAMES_WITHOUT_CFG=("${FILES_NAMES[#]%.cfg}") ## No .cfg extension.
if [[ FILES_COUNT -gt 0 ]]; then
printf "File: %s\n" "${FILES[#]}"
printf "Name: %s\n" "${FILES_NAMES[#]}"
printf "Name (no .cfg): %s\n" "${FILES_NAMES_WITHOUT_CFG[#]}"
printf "Total: %d\n" "$FILES_COUNT"
fi
Note that each entry has the same index number. So ${FILES[1]} is ${FILES_NAMES[1]} and also ${FILES_NAMES_WITHOUT_CFG[1]}. Entries begin with index 0.
You can also have other details through this:
if [[ FILES_COUNT -gt 0 ]]; then
for I in "${!FILES[#]}"; do
printf "File: %s\n" "${FILES[I]}"
printf "Name: %s\n" "${FILES_NAMES[I]}"
printf "Name (no .sh): %s\n" "${FILES_NAMES_WITHOUT_CFG[I]}"
printf "Index number: $I\n\n"
done
printf "Total: %d\n" "$FILES_COUNT"
fi
I've always liked abusing a for loop for a situation like this.
for x in *.cfg; do
[[ -f $x ]] && code_to_initialize_array
break
The explicit break means the loop iterates only once, no matter how many .cfg files you have. If you have none, *.cfg will be treated literally, so the [[ -f $x ]] checks if the "first" cfg file actually exists before trying to run code_to_initialize_array.
I'm attempting to write a script that calls another script and uses it either once, or in a loop, depending on the inputs.
I wrote a script that simply searches a file for a pattern and then prints the file name and lists the lines that the search was found on. That script is here
#!/bin/bash
if [[ $# < 2 ]]
then
echo "error: must provide 2 arguments."
exit -1
fi
if [[ -e $2 ]]
then
echo "error: second argument must be a file."
exit -2
fi
echo "------ File =" $2 "------"
grep -ne $1 $2
So now I want to write a new script that will call this is the user enters just one file as a second argument, and will also loop and search all the files in the directory if they select a directory.
So if the input is:
./searchscript if testfile
it'll just use the script but if the input is:
./searchscript if Desktop
It'll search all the files in a loop.
My heart runnith over for you all, as always.
something like could works:
#!/bin/bash
do_for_file() {
grep "$1" "$2"
}
do_for_dir() {
cd "$2" || exit 1
for file in *
do
do_for "$1" "$file"
done
cd ..
}
do_for() {
where="file"
[[ -d "$2" ]] && where=dir
do_for_$where "$1" "$2"
}
do_for "$1" "$2"
How about this:
#!/bin/bash
dirSearch() {
for file in $(find $2 -type f)
do
./searchscript $file
done
}
if [ -d $2 ]
then
dirSearch
elif [ -e $2 ]
then
./searchscript $2
fi
Alternatively if you don't want to parse the output of find you can do the following:
#!/bin/bash
if [ -d $2 ]
then
find $2 -type f -exec ./searchscript {} \;
elif [ -e $2 ]
then
./searchscript $2
fi
er... maybe too simple, but what about letting "grep" do all the work?
#myscript
if [ $# -lt 2 ]
then
echo "error: must provide 2 arguments."
exit -1
fi
if [ -e "$2" ]
then
echo "error: second argument must be a file."
exit -2
fi
echo "------ File =" $2 "------"
grep -rne "$1" "$2"
I just added "-r" to the grep invocation : if it's a file, no recursion, if it's a dir, it'll recurse on it.
You could even get rid of the argument checks and let grep barf the appropriate error messages : (keep the quotes or this will fail)
#myscript
grep -rne "$1" "$2"
Assuming you do not want to search recursively:
#!/bin/bash
location=shift
if [[ -d $location ]]
then
for file in $location/*
do
your_script $file
done
else
# Insert a check for whether $location is a real file and exists, if needed
your_script $location
fi
NOTE1: This has a subtle bug: if some files in the directory start with a ".", as far as i recall, "for *" loop will NOT see them, so you need to add "in $location/* $location/.*" instead
NOTE2: If you want recursive search, instead use find:
in `find $location`
I am trying to write a script in bash that check the validity of a user input.
I want to match the input (say variable x) to a list of valid values.
what I have come up with at the moment is:
for item in $list
do
if [ "$x" == "$item" ]; then
echo "In the list"
exit
fi
done
My question is if there is a simpler way to do this,
something like a list.contains(x) for most programming languages.
Say list is:
list="11 22 33"
my code will echo the message only for those values since list is treated as an array and not a string,
all the string manipulations will validate 1 while I would want it to fail.
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'
or create a function:
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}
to use it:
contains aList anItem
echo $? # 0: match, 1: failed
how about
echo $list | grep -w -q $x
you could either check the output or $? of above line to make the decision.
grep -w checks on whole word patterns. Adding -q prevents echoing the list.
Matvey is right, but you should quote $x and consider any kind of "spaces" (e.g. new line) with
[[ $list =~ (^|[[:space:]])"$x"($|[[:space:]]) ]] && echo 'yes' || echo 'no'
so, i.e.
# list_include_item "10 11 12" "2"
function list_include_item {
local list="$1"
local item="$2"
if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
# yes, list include item
result=0
else
result=1
fi
return $result
}
end then
`list_include_item "10 11 12" "12"` && echo "yes" || echo "no"
or
if `list_include_item "10 11 12" "1"` ; then
echo "yes"
else
echo "no"
fi
Note that you must use "" in case of variables:
`list_include_item "$my_list" "$my_item"` && echo "yes" || echo "no"
IMHO easiest solution is to prepend and append the original string with a space and check against a regex with [[ ]]
haystack='foo bar'
needle='bar'
if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
...
fi
this will not be false positive on values with values containing the needle as a substring, e.g. with a haystack foo barbaz.
(The concept is shamelessly stolen form JQuery's hasClass()-Method)
You can use (* wildcards) outside a case statement, too, if you use double brackets:
string='My string';
if [[ $string == *My* ]]
then
echo "It's there!";
fi
If it isn't too long; you can just string them between equality along a logical OR comparison like so.
if [ $ITEM == "item1" -o $ITEM == "item2" -o $ITEM == "item3" ]; then
echo In the list
fi
I had this exact problem and while the above is ugly it is more obvious what is going on than the other generalized solutions.
If your list of values is to be hard-coded in the script, it's fairly simple to test using case. Here's a short example, which you can adapt to your requirements:
for item in $list
do
case "$x" in
item1|item2)
echo "In the list"
;;
not_an_item)
echo "Error" >&2
exit 1
;;
esac
done
If the list is an array variable at runtime, one of the other answers is probably a better fit.
There's a cleaner way to check if string is in the list:
if [[ $my_str = #(str1|str2|str3) ]]; then
echo "string found"
fi
Consider exploiting the keys of associative arrays. I would presume this outperforms both regex/pattern matching and looping, although I haven't profiled it.
declare -A list=( [one]=1 [two]=two [three]='any non-empty value' )
for value in one two three four
do
echo -n "$value is "
# a missing key expands to the null string,
# and we've set each interesting key to a non-empty value
[[ -z "${list[$value]}" ]] && echo -n '*not* '
echo "a member of ( ${!list[*]} )"
done
Output:
one is a member of ( one two three )
two is a member of ( one two three )
three is a member of ( one two three )
four is *not* a member of ( one two three )
If the list is fixed in the script, I like the following the best:
validate() {
grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}
Then use validate "$x" to test if $x is allowed.
If you want a one-liner, and don't care about whitespace in item names, you can use this (notice -w instead of -x):
validate() { echo "11 22 33" | grep -F -q -w "$1"; }
Notes:
This is POSIX sh compliant.
validate does not accept substrings (remove the -x option to grep if you want that).
validate interprets its argument as a fixed string, not a regular
expression (remove the -F option to grep if you want that).
Sample code to exercise the function:
for x in "item 1" "item2" "item 3" "3" "*"; do
echo -n "'$x' is "
validate "$x" && echo "valid" || echo "invalid"
done
I find it's easier to use the form echo $LIST | xargs -n1 echo | grep $VALUE as illustrated below:
LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
...
fi
This works for a space-separated list, but you could adapt it to any other delimiter (like :) by doing the following:
LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
...
fi
Note that the " are required for the test to work.
Thought I'd add my solution to the list.
# Checks if element "$1" is in array "$2"
# #NOTE:
# Be sure that array is passed in the form:
# "${ARR[#]}"
elementIn () {
# shopt -s nocasematch # Can be useful to disable case-matching
local e
for e in "${#:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
# Usage:
list=(11 22 33)
item=22
if elementIn "$item" "${list[#]}"; then
echo TRUE;
else
echo FALSE
fi
# TRUE
item=44
elementIn $item "${list[#]}" && echo TRUE || echo FALSE
# FALSE
The shell built-in compgen can help here. It can take a list with the -W flag and return any of the potential matches it finds.
# My list can contain spaces so I want to set the internal
# file separator to newline to preserve the original strings.
IFS=$'\n'
# Create a list of acceptable strings.
accept=( 'foo' 'bar' 'foo bar' )
# The string we will check
word='foo'
# compgen will return a list of possible matches of the
# variable 'word' with the best match being first.
compgen -W "${accept[*]}" "$word"
# Returns:
# foo
# foo bar
We can write a function to test if a string equals the best match of acceptable strings. This allows you to return a 0 or 1 for a pass or fail respectively.
function validate {
local IFS=$'\n'
local accept=( 'foo' 'bar' 'foo bar' )
if [ "$1" == "$(compgen -W "${accept[*]}" "$1" | head -1)" ] ; then
return 0
else
return 1
fi
}
Now you can write very clean tests to validate if a string is acceptable.
validate "blah" || echo unacceptable
if validate "foo" ; then
echo acceptable
else
echo unacceptable
fi
Prior answers don't use tr which I found to be useful with grep. Assuming that the items in the list are space delimited, to check for an exact match:
echo $mylist | tr ' ' '\n' | grep -F -x -q "$myitem"
This will return exit code 0 if the item is in the list, or exit code 1 if it isn't.
It's best to use it as a function:
_contains () { # Check if space-separated list $1 contains line $2
echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
}
mylist="aa bb cc"
# Positive check
if _contains "${mylist}" "${myitem}"; then
echo "in list"
fi
# Negative check
if ! _contains "${mylist}" "${myitem}"; then
echo "not in list"
fi
Late to the show? Following very easy variant was not clearly mentioned yet. I use case for checking simple lists, which is a general Bourne Shell idiom not relying on anything external nor extended:
haystack='a b c'
needle='b'
case " $haystack " in (*" $needle "*) :;; (*) false;; esac
Please note the use of the separator (here: SPC) to correcyly delimit the pattern: At the beginning and end of " $haystack " and likewise in the test of " $needle ".
This statement returns true ($?=0) in case $needle is in $haystack, false otherwise.
Also you can test for more than one $needle very easily. When there are several similar cases like
if (haystack.contains(needle1)) { run1() } elif (haystack.contains(needle2)) { run2() } else { run3() }
you can wrap this into the case, too:
case " $haystack " in (*" $needle1 "*) run1;; (*" $needle2 "*) run2;; (*) run3;; esac
and so on
This also works for all lists with values which do not include the separator itself, like comma:
haystack=' a , b , c '
needle=' b '
case ",$haystack," in (*",$needle,"*) :;; (*) false;; esac
Note that if values can contain anything including the separator sequence (except NUL, as shells do not suport NUL in variables as you cannot pass arguments containing NUL to commands) then you need to use arrays. Arrays are ksh/bashisms and not supported by "ordinary" POSIX/Bourne shells. (You can work around this limitation using $# in POSIX-Shells, but this is something completely different than what was aked here.)
Can the (*) false part be left away?
No, as this is the critical return value. By default case returns true.
Yes if you do not need the return value and put your processing at the location of the :
Why the :;;
We could also write true;;, but I am used to use : instead of true because it is shorter and faster to type
Also I consider not writing anything bad practice, as it is not obvious to everybody that the default return value of case is true.
Also "leaving out" the command usually indicates "something was forgotten here". So putting a redundant ":" there clearly indicates "it is intended to do nothing else than return true here".
In bash you can also use ksh/bashisms like ;& (fallthroug) or ;;& (test other patterns) to express if (haystack.contains(needle1)) { run1(); }; if (haystack.contains(needle2)) { run2(); }
Hence usually case is much more maintainable than other regex constructs. Also it does not use regex, it only use shell patterns, which might even be faster.
Reusable function:
: Needle "list" Seperator_opt
NeedleListSep()
{
if [ 3 -gt $# ];
then NeedleListSep "$1" "$2" " ";
else case "$3$2$3" in (*"$3$1$3"*) return 0;; esac; return 1;
fi;
}
In bash you can simplify this to
: Needle "list" Seperator_opt
NeedleListSep()
{
local s="${3-" "}";
case "$s$2$s" in (*"$s$1$s"*) return 0;; esac; return 1;
}
Use like this
Test() {
NeedleListSep "$1" "a b c" && echo found $1 || echo no $1;
NeedleListSep "$1" "a,b,c" ',' && echo found $1 || echo no $1;
NeedleListSep "$1" "a # b # c" ' # ' && echo found $1 || echo no $1;
NeedleListSep "$1" "abc" '' && echo found $1 || echo no $1;
}
Test a
Test z
As shown above, this also works for degerated cases where the separator is the empty string (so each character of the list is a needle). Example:
Test
returns
no
no
no
found
As the empty string is cleary part of abc in case your separator is the empty string, right?
Note that this function is Public Domain as there is absolutely nothing to it which can be genuinely copyrighted.
An alternative solution inspired by the accepted response, but that uses an inverted logic:
MODE="${1}"
echo "<${MODE}>"
[[ "${MODE}" =~ ^(preview|live|both)$ ]] && echo "OK" || echo "Uh?"
Here, the input ($MODE) must be one of the options in the regular expression ('preview', 'live', or 'both'), contrary to matching the whole options list to the user input. Of course, you do not expect the regular expression to change.
Examples
$ in_list super test me out
NO
$ in_list "super dude" test me out
NO
$ in_list "super dude" test me "super dude"
YES
# How to use in another script
if [ $(in_list $1 OPTION1 OPTION2) == "NO" ]
then
echo "UNKNOWN type for param 1: Should be OPTION1 or OPTION2"
exit;
fi
in_list
function show_help()
{
IT=$(CAT <<EOF
usage: SEARCH_FOR {ITEM1} {ITEM2} {ITEM3} ...
e.g.
a b c d -> NO
a b a d -> YES
"test me" how "test me" -> YES
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ "$#" -eq 0 ]; then
show_help
fi
SEARCH_FOR=$1
shift;
for ITEM in "$#"
do
if [ "$SEARCH_FOR" == "$ITEM" ]
then
echo "YES"
exit;
fi
done
echo "NO"
Assuming TARGET variable can be only 'binomial' or 'regression', then following would do:
# Check for modeling types known to this script
if [ $( echo "${TARGET}" | egrep -c "^(binomial|regression)$" ) -eq 0 ]; then
echo "This scoring program can only handle 'binomial' and 'regression' methods now." >&2
usage
fi
You could add more strings into the list by separating them with a | (pipe) character.
Advantage of using egrep, is that you could easily add case insensitivity (-i), or check more complex scenarios with a regular expression.
This is almost your original proposal but almost a 1-liner. Not that complicated as other valid answers, and not so depending on bash versions (can work with old bashes).
OK=0 ; MP_FLAVOURS="vanilla lemon hazelnut straciatella"
for FLAV in $MP_FLAVOURS ; do [ $FLAV == $FLAVOR ] && { OK=1 ; break; } ; done
[ $OK -eq 0 ] && { echo "$FLAVOR not a valid value ($MP_FLAVOURS)" ; exit 1 ; }
I guess my proposal can still be improved, both in length and style.
Simple oneliner...
if [[ " 11 22 33 " == *" ${x} "* ]]; then echo "${x} is in the list"; fi;
Add before fi: else echo "${x} is NOT in the list";
The script below implements contains function for a list.
function contains {
local target=$1
shift
printf '%s\n' "$#" | grep -x -q "$target"
out=$?
(( out = 1 - out ))
return $out
}
If you convert a string based on white space into a list and use it, it seems to be solved as follows.
list="11 22 33"
IFS=" " read -ra parsed_list <<< "$list"
# parsed_list would be ("11" "22" "33")
contains "11" "${parsed_list[#]}"
echo $? # 1
contains "22" "${parsed_list[#]}"
echo $? # 1
contains "1" "${parsed_list[#]}"
echo $? # 0
contains "11 22" "${parsed_list[#]}"
echo $? # 0