#!/bin/bash -x
echo "enter an integer "
read $val
for((i=0;i<=2;i++))
do
Numbers[$i]=$val
done
echo ${Number[#]}
if [ $((${Number[0]}+${Number[1]}+${Number[2]})) -eq 0 ]
then
echo "Sum is Zero"
else
echo "Sum is not zero"
fi
Couple of problems:
#!/bin/bash -x
echo "enter an integer "
read val # read takes the name of a variable
for((i=0;i<=2;i++))
do
Numbers[$i]=$val
done
echo ${Numbers[#]} # from here on, you wrote "Number" instead of "Numbers"
if [ $((Numbers[0] + Numbers[1] + Numbers[2])) -eq 0 ] # you don't need $ to read variables in arithmetic expansions
then
echo "Sum is Zero"
else
echo "Sum is not zero"
fi
Related
thanks for your help.
What a I doing wrong, here ? I want the numeric answer to be used in a loop but it does not return what I expected :
if [ "$#" -eq 0 ]; then
echo -n "Enter the number: "
read answer
else
answer=( "$#" )
fi
for i in {1..$answer} ; do echo ${i}; done
When executed, I have this:
me#local misc]$ ./test.sh
Enter the number: 5
{1..5}
I expected the echo to return 1 2 3 4 5
You can also do it like:
if [ "$#" -eq 0 ]; then
echo -n "Enter the number: "
read answer
else
answer=( "$#" )
fi
for i in $(seq 1 $answer) ; do echo ${i}; done
With no proposed answer I decided to switch to bash with that syntax that works (though it bothers me)
for (( i=1 ; i<=${answer} ; i++));
Folks,
I have an array, ex,
declare -a arr=("crm" "hr" "pos")
I need to output error if the passed value doesn't exist in this array
I'm trying this use below snippet but it prints "No match found" for any value
match=0
for i in "${arr[#]}"; do
if ! [[ $2 == "$i" ]]; then
match=1
break
fi
done
if [[ $match = 1 ]]; then
echo "No match found"
fi
Any idea how to loop in array and popup error if value doesn't exist ?
There are already answers about your question see check value is in an array, but a fix/idea for your specific approach is something like.
#!/usr/bin/env bash
declare -a arr=("crm" "hr" "pos")
match=0
for i in "${arr[#]}"; do
if ! [[ $2 == "$i" ]]; then
((match++))
fi
done
if (( match == ${#arr[*]} )); then
printf >&2 "No match found\n"
fi
The above script increments match every time the test inside the for loop is true, and in the end compare match with the length of the array ${#arr[*]}. A more verbose output is to put set -x on after the shebang and add a $ sign to the variable match (which is not required) inside the (( )).
if (( $match == ${#arr[*]} )); then
Your original approach always breaks the loop when it does not have a match, doing so will not continue the loop.
You reversed the logic. Just leave out the ! and swap the final test:
match=0
for i in "${arr[#]}"; do
if [[ $2 == "$i" ]]; then
match=1
break
fi
done
if [[ $match = 0 ]]; then
echo "No match found"
fi
This doesn't require a loop.
c.f. if a 2 strings BOTH present in 1 array in a bash script
$: x=bar
$: [[ " ${arr[*]} " =~ " $x " ]] && echo found || echo nope
nope
$: x=hr
$: [[ " ${arr[*]} " =~ " $x " ]] && echo found || echo nope
found
or
$: match=0
$: set -- foo bar
$: [[ " ${arr[*]} " =~ " $2 " ]] && match=1
$: echo match
0
$: set -- foo crm
$: [[ " ${arr[*]} " =~ " $2 " ]] && match=1
$: echo match
1
The logic seems incorrect.
If it does not match, you break the loop.
If it does match, the loop goes to the next iteration. Then it becomes unmatched and finally breaks the loop
declare -a arr=("crm" "hr" "pos")
not_match=0
for i in "${arr[#]}"; do
if [ "$2" = "$i" ]; then
not_match=1
break
fi
done
if [ $not_match -eq 0 ]; then
echo "No match found"
fi
I am trying to compare an array with a value and print an error statement if the match is not found.
arraylist="$(ls new-dir/ | cut -d' ' -f1)"
For example, this stores values such as small, large and medium which are the files present in new-dir.
The value to be compared with will be entered by the user viz. var
I have tried something like following:
(for i in "${arraylist[#]}"; do [[ "$i" == "$var"]] && exit 0; done) && echo "found" || echo "not found"
Also tried, however, doesn't work:
arraylist="$(ls new-dir/ | cut -d' ' -f1)"
count=0
for((i=0; i<${#arraylist[#]}; i++)); do
if [ "$arraylist[$i]" == "$var" ] ; then
count=1
fi
done
if [ $count -eq 0 ]; then
echo "Not found"
fi
Is there any other way to do this comparison?
This code works. Just replace arraylist with your array.
arraylist=('hello' 'world')
var='hello'
count=0
for i in "${arraylist[#]}"
do
if [ "$i" == "$var" ]; then
count=1
fi
done
if [ $count -eq 0 ]; then
echo "Not found"
fi
To extract the first "word" from each filename, I'd do
declare -A prefixes
cd new-dir
for file in *; do
read -r prefix _ <<< "$file"
prefixes["$prefix"]=1
done
cd -
then to look for a match:
# $var is somehow provided
result=""
for p in "${!prefixes[#]}"; do
if [[ $p == "$var" ]]; then
result=found
break
fi
done
echo "${result:-not found}"
This requires bash v4.0+ for the use of an associative array.
If you have bash v4.3+ you can do
[[ -v prefixes[$var] ]] && echo found || echo not found
Alternately:
shopt -s nullglob
files=( new-dir/"$var "* )
(( ${#files[#]} > 0 )) && echo found || echo not found
This is what shell programming is about. Keep it simple :
Array1=( "item1" "item2" "item3" "item-4" )
var="item3"
count=$(echo ${Array1[#]} | tr ' ' '\n' | awk '$1 == "'"$var"'"{print $0}' | wc -l)
[ $count -eq 0 ] && echo "Not found" || echo "found"
The arraylist might be an array with just one index.
The command:
arraylist="$(ls new-dir/ | cut -d' ' -f1)"
might just assign whole "ls new-dir" output to ${arraylist[0]}
You can check the index value in an array by echo ${arraylist[1]} (to confirm).
Try changing the command to generate an array for a list of files/dirs to:
arraylist=($(ls new-dir/))
The complete script:
arraylist=($(ls new-dir/))
(for i in "${arraylist[#]}"; do [[ "$i" == "$var" ]] && exit 0; done) && echo "found" || echo "not found"
You can also ignore the whole array assignment and just use subshell-command in for loop, eg:
(for i in $(ls -1 new-dir/); do [[ "$i" == "$var" ]] && exit 0; done) && echo "found" || echo "not found"
Remember, no quotes " around $(ls -1 new-dir/)
Another one-liner without any array or loops:
ls -1 new-dir/ | grep -q "$var" && echo "found" || echo "not found"
Edit:
As #M. Nejat Aydin suggested, use [[ -e new-dir/$var ]] && echo "found" || echo "Not found" and do not use ls in the script.
I am trying to test User input with password rules.
must be at least 8 characters long but not longer than 16 characters.
must contain at least 1 digit (0-9).
must contain at least 1 lowercase letter.
must contain at least 1 uppercase letter.
must contain exactly one and only one of #, #, $, %, &, *, +, -, =.
I'm trying to figure how I can compare the user string to the arrays that contain the password characters.
#!/bin/bash
Upper=("A""B""C""D""E""F""G""H""I""J""K""L""M""N""O""P""Q""R""S""T""U""V""W""X""Y""Z")
Lower=("a""b""c""d""e""f""g""h""i""j""k""l""m""o""p""q""r""s""t""u""v""w""x""y""z")
Numbers=("1""2""3""4""5""6""7""8""9")
SpecialChar=("&""#""#""$""%""*""-""+""=")
# Password Generator
PassGen(){ # generate password if no user input
Pwlength=`shuf -i 8-16 -n 1` # holds the range/length of password
Password=`< /dev/urandom tr -dc A-Za-z0-9$SpecialChar | head -c $Pwlength`
echo "Random Password is being generated for you"
sleep 5
echo "Your new password is : $Password"
echo exit?
}
# I want to make the following to work :
\#PassGen2(){ # generate password 2 if no user input
\#if [ $# -eq 0 ] ; then
\#for ((i=0;i<4;i++))
\#do
\#password="${Upper[$random % ${#Upper[#]}" ] }
\#password="${Lower[$random % ${#Lower[#]}" ] }
\#password="${Numbers[$random % ${#Numbers[#]}" ] }
\#done
\#password="${SpecialChar[$random % ${#SpecialChar[#]}" ] }
\#password="${Upper[$random % ${#Upper[#]}" ] }
\#echo "Random Password is being generated for you"
\#sleep 5
\#echo "Your new password is : $Password"
\#fi
\#echo exit?
\#}
# Help menu
Usage(){ # Help menu
echo "The password must meet the following :"
echo "> must be at least 8 characters long but not longer than 16 characters."
echo "> must contain at least 1 digit (0-9)."
echo "> must contain at least 1 lowercase letter."
echo "> must contain at least 1 uppercase letter."
echo "> must contain exactly one and only one of # # $ % & * + - ="
echo ""
echo " * * IF NO PASSWORD IS ENTERED THE SYSTEM WILL GENERATE A PASSPORD FOR YOU * * "
echo exit?
}
#The main starts here
if [ $# -eq 0 ] ; then
PassGen $SpecialChar
fi
if [ $# == "-h"] ; then
Usage
fi
UserPW=$1 # assigning the firsth positional parameter to variable (password)
#The reason I open the post
PwCheck(){
if [[ ${#UserPW} < 8 && ${#UserPW} > 0 ]] ;then #check the lower end of the password
echo "Password have to be more then 8 character"
exit 1
fi
if [[ ${#UserPW} < 16 ]] ;then #checks if the password bigger then 16 character
echo "Password too long ! - Password have to be between 8 - 16 characters"
exit 1
fi
if [[ ${#UserPW} < 17 && ${#UserPW} > 8 ]] ; then
Pwarr=($UserPW) # putting the variable into Array
for (( i=0; i < ${#Upper[#]};i++ ))
do
if [[ ${Pwarr[0]:[i]:1} != ${Upper[i]} ]]; then
echo "You have to enter at least 1 upper character letter"
exit 1
fi
done
for (( i=0; i < ${#Lower[#]};i++ ))
do
if [[ ${Pwarr[0]:[i]:1} != ${Lower[i] ]]; then
echo "You have to enter at least 1 Lower character letter"
exit 1
fi
done
for (( i=0; i < ${#SpecialChar[#];i++ ))
do
if [[ ${Pwarr[0]:[i]:1} != ${SpecialChar[i] ]] ;then
echo " You have to enter at least 1 special character
exit 1
fi
done
#}
My problems:
I couldn't make my PassGen2() to work beside "calling it". I know
there must be typo or syntax errors.
For PwCheck() function I know I didn't call it and the IF
statement should be in the main section.
It's easier to implement PwCheck leaving the user password as a string rather than converting it to an array:
bad_length(){
l=`wc -c`
[ $l -ge 8 ] && [ $l -le 16 ] && return 1 || return 0
}
no_digit(){
grep -q '[0-9]' && return 1 || return 0
}
no_lc(){
grep -q '[a-z]' && return 1 || return 0
}
no_uc(){
grep -q '[A-Z]' && return 1 || return 0
}
specials='##$%&*+=-'
no_exactly_one_special(){
n=`grep -o "[$specials]" | wc -l`
[ $n -eq 1 ] && return 1 || return 0
}
echo "$1" | bad_length && echo 'Password must be between 8 - 16 characters' && exit 1
echo "$1" | no_digit && echo 'Password must have at least one number 0-9' && exit 1
echo "$1" | no_lc && echo 'Password must have at least one lowercase letter' && exit 1
echo "$1" | no_uc && echo 'Password must have at least one UPPERCASE letter' && exit 1
echo "$1" | no_exactly_one_special && echo "Password must have exactly one special character: $specials" && exit 1
exit 0
A few words of explanation:
First, it is possible in bash to pipe (using |) to a function:
no_digit_from_stdin(){
grep -q '[0-9]' && return 1 || return 0
}
echo "abc" | no_digit_from_stdin && echo $?
instead of passing it as an argument:
no_digit_from_arg(){
echo "$1" | grep -q '[0-9]' && return 1 || return 0
}
no_digit_from_arg "abc" && echo $?
These two have the same outcome here.
Second, it is possible to use pipes and && to control flow concisely. So this:
echo "$1" | no_digit_from_stdin && echo 'Password must have at least one number 0-9' && exit 1
has the same outcome as this:
if no_digit_from_arg "$1"; then
echo 'Password must have at least one number 0-9'
exit 1
fi
...but these are matters of style and not directly relevant to your question.
Here is a version of my answer that you may find more usable, with a secret bonus feature:
PwCheck(){
pass=true
l=`echo "$UserPW" | wc -c`
if [ $l -lt 8 ] || [ $l -gt 16 ]; then
echo 'Password must be between 8 - 16 characters'
pass=false
fi
if ! echo "$UserPW" | grep -q '[0-9]'; then
echo 'Password must have at least one number 0-9'
pass=false
fi
if ! echo "$UserPW" | grep -q '[a-z]'; then
echo 'Password must have at least one lowercase letter'
pass=false
fi
if echo "$UserPW" | grep -q '[A-Z]'; then
echo 'Password must have at least one UPPERCASE letter'
pass=false
fi
specials='##$%&*+=-'
n=`echo "$UserPW" | grep -o "[$specials]" | wc -l`
if [ $n -ne 1 ]; then
echo "Password must have exactly one special character: $specials"
pass=false
fi
if $pass; then
exit 0
else
exit 1
fi
}
I'm writing a simple calculator in BASH. Its aim is to loop through the arguments given, check if they're correct, do the power function and pass the rest to the expr to do the calculation. Everything except multiplication works.
When I do something like
my_script.sh 2 \* 2
I get syntax error from expr. Checking with bash -x lets me know that
expr 2 '\*' 2
The * is in apostrophes. I don't know how to get rid of it so the expr can parse it properly.
if [ $# -le 0 ]
then
usage
exit 1
fi
ARGS=("${#}")
while [ $# -gt 0 ]
do
if [ $OP -eq 0 ]
then
if [[ $1 =~ ^[-]{0,1}[0-9]+$ ]]
then
ELEMS[$J]=$1
shift
let OP=1
let J=$J+1
else
echo $1' is not a number'
usage
exit 3
fi
else
if [[ $1 =~ ^[-+/\^\*]{1}$ ]]
then
if [[ $1 =~ ^[\^]{1}$ ]]
then
if ! [[ $2 =~ ^[0-9]+$ ]]
then
echo 'Bad power exponent'
usage
exit 3
fi
let BASE=${ELEMS[$J-1]}
let EX=$2
pow $BASE $EX
let ELEMS[$J-1]=$RES
shift 2
else
if [[ $1 =~ [\*]{1} ]]
then
ELEMS[$J]=\\*
else
ELEMS[$J]=$1
fi
let J=$J+1
shift
let OP=0
fi
else
echo $1' is not an operator'
if [[ $1 =~ ^[0-9]+$ ]]
then
let TMP=${ELEMS[$J-1]}
echo "Are you missing an operator beetwen $TMP and $1?"
fi
usage
exit 3
fi
fi
done
if [ $OP -eq 0 ]
then
echo 'Missing argument after last operator'
usage
exit 3
fi
echo "Calculation: ${ARGS[*]}"
echo -n 'Result: '
expr ${ELEMS[*]}
Change ELEMS[$J]=\\* to ELEMS[$J]="*" (or ELEMS[$J]=\*) and use:
expr "${ELEMS[#]}"
The key is to use # instead of * in the array dereference, which allows you to use double quotes. This is equivalent to expr "2" "*" "2", instead of expr "2 * 2" which you get when using expr "${ELEMS[*]}"