I have the following code to count the number of how many times the name occurred in one file. The code is working fine and the output is exactly what I want. The problem is the real code has more than 50 names in function listname which cause function name to have more than 50 case ,and function setname more than 50 lines.
is there a way to rewrite function name and function setname in short code? someone told me I can use Array but not sure how. My goal is to reduce the number of lines.
function listname {
echo "List of Name:-"
echo "1-Kim 2-Lee 3-Jack 4-Sam"
echo "5-Nick 6-Smith"
name;
}
function name {
echo "Which name ou want to change?"
read iname
case $iname in
1 ) echo "Kim"
read -p "Enter Kim: " Kim
echo "Kim=($Kim)"
;;
2 ) echo "Lee"
read -p "Enter Lee: " Lee
echo "Lee=($Lee)"
;;
3 ) echo "Jack"
read -p "Enter Jack: " Jack
echo "Jack=($Jack)"
;;
4 ) echo "Sam"
read -p "Enter Sam: " Sam
echo "Sam=($Sam)"
;;
5 ) echo "Nick"
read -p "Enter Nick: " Nick
echo "Nick=($Nick)"
;;
6 ) echo "Smith"
read -p "Enter Smith: " Smith
echo "Smith=($Smith)"
;;
* ) echo "You did not enter a number"
echo "between 1 and 6."
esac
echo "Do you want another change?"
read anothchang
case $anothchang in
[yY] | [yY][Ee][Ss] )
listname;
;;
[nN] | [nN][Oo] )
setname;
}
function setname {
[ -z "$Kim" ] && Kim="cat /tmp/list | grep -c Kim"
[ -z "$Lee" ] && Lee="cat /tmp/list | grep -c Lee"
[ -z "$Jack" ] && Jack="cat /tmp/list | grep -c Jack"
[ -z "$Sam" ] && Sam="cat /tmp/list | grep -c Sam"
[ -z "$Nick" ] && Nick="cat /tmp/list | grep -c Nick"
[ -z "$Smith" ] && Smith="cat /tmp/list | grep -c Smith"
output;
}
function output {
echo "Kim ($Kim)
Lee($Lee)
Jack($Jack)
Sam($Sam)
Nick($Nick)
Smith($Smith)"
}
echo "Hello"
listname;
I don't think above code is working fine. Having corrected several logical and syntactical errors, I'm still not sure I understand what you are doing - you have a list of six name constants, and six variables named identically. The latter are used to hold either a character string alternative name to be read from stdin (user terminal) or, if that is missing, an integer word count for, again, text constants. In the end, if an alternate name is entered, you output that, otherwise the word count for the respective text constant in a /tmp file. On top, your recursive use of functions is somewhat unorthodox.
Assuming you have a recent bash, and names in a file like
Kim
Lee
Jack
Sam
Nick
Smith
, try this
mapfile -tO1 ORIG <file
mapfile -tO1 NAMES <file
select NAME in ${NAMES[@]}
do [ $REPLY -eq 0 ] && break
read -p "Enter ${NAMES[$REPLY]} " NAMES[$REPLY]
done
for i in ${!ORIG[@]}
do printf "%s(" ${ORIG[$i]}
[ "${ORIG[$i]}" == "${NAMES[$i]}" ] &&
printf "%s)\n" $(grep -c ${NAMES[$i]} /tmp/list) ||
printf "%s)\n" "${NAMES[$i]}"
done
i apologize for the misunderstanding , this is not the really code. I just wrote the above code to gave you in idea of what I am trying to do.
I fixed the code above , and now should run. Let say here is what inside my list file:-
cat list
Sam
Sam
Kim
Sam
Kim
Jack
Nick
Nick
Smith
Smith
when I run the code :-
List of Name:-
1-Kim 2-Lee 3-Jack 4-Sam
5-Nick 6-Smith
Which name ou want to change?
1
Kim
Enter Kim: 23
Kim=(23)
Kim (23)
Lee(0)
Jack(1)
Sam(3)
Nick(2)
Smith(2)
The code is running fine , I just want it to know if there is any way to rewrite it in short way.
here is the updated code
function listname {
echo "List of Name:-"
echo "1-Kim 2-Lee 3-Jack 4-Sam"
echo "5-Nick 6-Smith"
name;
}
function name {
echo "Which name ou want to change?"
read iname
case $iname in
1 ) echo "Kim"
read -p "Enter Kim: " Kim
echo "Kim=($Kim)"
;;
2 ) echo "Lee"
read -p "Enter Lee: " Lee
echo "Lee=($Lee)"
;;
3 ) echo "Jack"
read -p "Enter Jack: " Jack
echo "Jack=($Jack)"
;;
4 ) echo "Sam"
read -p "Enter Sam: " Sam
echo "Sam=($Sam)"
;;
5 ) echo "Nick"
read -p "Enter Nick: " Nick
echo "Nick=($Nick)"
;;
6 ) echo "Smith"
read -p "Enter Smith: " Smith
echo "Smith=($Smith)"
;;
* ) echo "You did not enter a number"
echo "between 1 and 6."
esac
setname;
}
function setname {
[ -z "$Kim" ] && Kim=`cat list | grep -c Kim`
[ -z "$Lee" ] && Lee=`cat list | grep -c Lee`
[ -z "$Jack" ] && Jack=`cat list | grep -c Jack`
[ -z "$Sam" ] && Sam=`cat list | grep -c Sam`
[ -z "$Nick" ] && Nick=`cat list | grep -c Nick`
[ -z "$Smith" ] && Smith=`cat list | grep -c Smith`
output;
}
function output {
echo "Kim ($Kim)
Lee($Lee)
Jack($Jack)
Sam($Sam)
Nick($Nick)
Smith($Smith)"
}
echo "Hello"
listname;
#!/bin/bash
#
#
# Variables
#
declare -A AGE # Create an associative array
NAMES="Kim Lee Jack Sam Nick Smith" # List with names
#
# Fill the array
#
select name in Back $NAMES;do # Select an entry of the list NAMES
[[ $name = Back ]] && break # Exit the select-loop / break out
echo "Hello $name, what is your age?"
read age
AGE[$name]=$age # Set the arrays entry '$name' to value '$age'
done
#
# Output the content
#
for n in $NAMES
do
echo "$n is ${AGE[$n]} years old"
done
echo "Have a nice day :)"
You have to be careful not to enter a number that is out of range. (zero or greater than the size of the list)
I made a few changes to catch that error and another bug I discovered...
function name {
echo
echo "Which name you want to change? "
read iname
[ $iname ] || output; # No entry = exit
if [ $iname -gt $SIZE ] || [ $iname -lt 1 ]; then
echo "Choice is out of range"
listname;
fi
function listname {
num=0
for x in ${NAMES
[*]};
do
num=$(( $num + 1 ))
printf "%d-%s" $num $x
if [[ $(( $num % 4 )) -ne 0 ]]; then # 4 column display
printf "\t"
else
printf "\n"
fi
SIZE=$num
done
NAMES=($(cat names.data | sort -u)) # unique names array
SIZE=0
function output {
echo
for x in ${NAMES
[*]};
do
echo "$x(${AGES[$x]})"
done
exit
}
I really appreciate your help , I am still getting the following error:-
$ ./test2
Hello
1-Jack(12) 2-Kim(22) 3-Nick(89) 4-Sam(78)
5-Smith(7)
Which name you want to change?
4
Enter : 21
./test2: line 49: AGES[$nam]: bad array subscript
Here is how the code like:-
#!/bin/sh
declare -A AGES # associative name/ages array
NAMES=($(cat list | sort -u)) # unique names array
SIZE=0
function output {
echo
for x in ${NAMES
[*]};
do
echo "$x(${AGES[$x]})"
done
exit
}
function setname {
for x in ${NAMES
[*]};
do
AGES[$x]=$(grep -c $x list)
done
}
function listname {
num=0
for x in ${NAMES
[*]};
do
num=$(( $num + 1 ))
printf "%d-%s" $num $x
if [[ $(( $num % 4 )) -ne 0 ]]; then # 4 column display
printf "\t"
else
printf "\n"
fi
SIZE=$num
done
name;
}
function name {
echo
echo "Which name you want to change? "
read iname
[ $iname ] || output; # No entry = exit
if [ $iname -gt $SIZE ] || [ $iname -lt 1 ]; then
echo "Choice is out of range"
listname;
fi
read -p "Enter $nam: " age
AGES[$nam]=$age # update AGES array
echo "$nam=(${AGES[$nam]})"
Here is another array implementation that might be closer to your original script:
NAMES=( Kim Lee Jack Sam Nick Smith )
function listname {
echo "List of Name:-"
for((i=1;i<=${#NAMES[@]};i++))
do
printf "%d-%-8s" $i "${NAMES[i-1]}"
((i%4==0)) && printf "\n"
done
printf "\n"
}
function name {
printf "\n"
read -p "Which name you want to change? " iname
if [ -n "$iname" -a $iname -gt 0 -a $iname -le ${#NAMES[@]} ] 2> /dev/null
then
nam="${NAMES[iname-1]}"
read -p "Enter $nam: " AGE[$iname-1]
else
echo "You did not enter a number"
echo "between 1 and ${#NAMES[@]}."
fi
echo
read -p "Do you want another change? " anothchang
[[ $anothchang = [yY] || $anothchang = [yY][Ee][Ss] ]]
}
function output {
for((i=0;i<${#NAMES[@]};i++))
do
printf "%s(%d)\n" "${NAMES}" ${AGE}
done
}
listname
while name
do
output
listname
done
output