What is wrong with my DOB Sorting script - bash

I keep getting an error on line 22: [!: command not found
My script Asks for a name, phone number, and date of birth and then amends these details to a comma separated value file called “birthday.csv”.
It then Sorts “birthday.csv” by date of birth. The newly sorted file is then displayed and calculates their age.
Can someone take a look at my script and see why this is popping up.
#!/bin/bash
a=0
while [ $a -lt 2 ];
do
echo Please enter a first name
read firstName
echo Please enter last name
read lastName
echo Please enter phone number
read phoneNumber
echo Please enter date of birth - format dd/mm/yyyy
read dob
echo "$firstName,$lastName,$phoneNumber,$dob" >> userBirthdays.csv
echo If you would like to add another person press 1 or enter 2 to proceed
read a
done
INPUT=./userBirthdays.csv
OLDIFS=$IFS
IFS=","
[! -f INPUT] & while read Name Surname Telephone DOB
do
birthMonth=${DOB:0:2}
birthDay=#10${DOB:3:2}
birthYear=${DOB:6:4}
currentDate=`date +%d/%m/%Y`
currentMonth=${currenDate:0:2}
currentDay=#10${currentDate:3:2}
currentYear=${currentDate:6:4}
if [[ "$currentMonth" -lt "$birthMonth" ]] || [[ "$currentMonth" -eq "$birthMonth" && "$((#10$currentDay))" -lt "$((#10$birthDay))" ]]
then
let Age=currentYear-birthYear-1
else
let Age=currentYear-birthYear
fi
echo "Name : $Name"
echo "Surname : $Surname"
echo "Telephone : $Telephone"
echo "DOB : $DOB"
echo "Age : $Age"
echo "##########################################"
done < $INPUT
IFS=$OLDIFS
echo $DATE
exit 0;
Thank you in advance

you need a space between between the [ and ! chars, i.e.
[ ! -f $INPUT ] && while read ....
#^-^--------^-^---^------------
Note that you almost certainly want two '&' chars, as in my correction.
Thanks to #GordonDavisson for another '$' ;-)
IHTH

Separate [ and ! with a space, so [ will be a command, and ! will be its first argument, as you meant them to be.
(Not sure there are no other problems).

Related

Bash script to download PDF using a CSV with name and url and auto-increment name

I'm trying to create a bash script that reads a CSV with two columns:
first column = name
second column = URL
and try to download a PDF file from the URL on the second column with a random name with letters and numbers .pdf and change the name using the first column.
The PDF name could be duplicate so if is duplicate I want to add numbers like:
Example %20 $5000.pdf
Example %20 $5000.1.pdf
Example %20 $5000.2.pdf
Because if I try to download wget and curl will not auto-increment with the output option.
I tried a lot of things but my limitations are taking too much time.
I created a counter that add the line number to the end, but if I got a larger PDF there will be unnecessary auto-increment numbers. (code below)
There should be a better method, but my lack of knowledge is taking too much time. So any help with that will be really appreciated, I'm a beginner on bash scripts.
Thanks for any help in advance!
CSV example:
Example %20 $5000,HTTP://example.com/djdiede.pdf
Example %20 $5000,HTTP://example.com/djdi42322ede.pdf
Example %30 $1000,HTTP://example.com/djd4234iede.pdf
Example %50 $1000,HTTP://example.com/dj43566diede.pdf
Code so far:
#!/bin/bash -e
COUNTER=1
while IFS=, read -r field1 field2
do
COUNTER=$[$COUNTER +1]
if [ "$field1" == "" ]
then
echo "Line $COUNTER field1 is empty or no value set"
elif [ "$field2" == "" ]
then
echo "Line $COUNTER field2 is empty or no value set"
else
pdf_file=$(echo $field1 | tr '/' ' ')
echo "================================================"
echo "Downloading $COUNTER $pdf_file..."
echo "================================================"
pdf_file_test="$pdf_file.pdf"
if [ -e "$pdf_file_test" ]; then
echo -e "\033[32m ^^^ File already exists!!! Adding line number at the end of the file: $pdf_file.$COUNTER.pdf \033[0m" >&2
wget -q -nc -O "$pdf_file."$COUNTER.pdf $field2
else
wget -q -nc -O "$pdf_file".pdf $field2
fi
fi
done < test.csv
This should help. I tried to stay close to your own coding style:
#!/bin/bash -e
LINECOUNTER=0
while IFS=, read -r field1 field2
do
LINECOUNTER=$[$LINECOUNTER +1]
if [ "$field1" == "" ]
then
echo "Line $LINECOUNTER: field1 is empty or no value set"
elif [ "$field2" == "" ]
then
echo "Line $LINECOUNTER: field2 is empty or no value set"
else
pdf_file=$(echo "$field1" | tr '/' ' ')
echo "================================================"
echo "Downloading $LINECOUNTER: $pdf_file..."
echo "================================================"
pdf_file_saveas="$pdf_file.pdf"
FILECOUNTER=0
while [ -e "$pdf_file_saveas" ]
do
FILECOUNTER=$[$FILECOUNTER +1]
pdf_file_saveas="$pdf_file.$FILECOUNTER.pdf"
done
if [ $FILECOUNTER -gt 0 ]
then
echo -e "\033[32m ^^^ File already exists!!! Adding number at the end of the file: $pdf_file_saveas \033[0m" >&2
fi
wget -q -nc -O "$pdf_file_saveas" "$field2"
fi
done < test.csv
Here's what I did:
use two counters: one for lines, one for files
when a file already exists, use file counter + loop to find the next 'empty slot' (i.e. file named <filename>.<counter-value>.pdf that does not exist)
fixed wrong line numbers (line counter needs to start at 0 instead of 1)
added double quotes where necessary/advisable
If you want to improve your script further, here are some suggestions:
instead of the big if ... elif ... else contruct, you can use if + continue, e.g. if [ "$field1" == "" ]; then continue; fi or even [ "$field1" == "" ] && continue
instead of terminating on error (#!/bin/bash -e), you could add error detection and handling after the wget call, e.g. if [ $? -ne 0 ]; then echo "failed to download ..."; fi

Insert Contacts to a .csv file using terminal and shell script

Hi I want to make a script that inserts contacts to a .csv file. It asks the user to type First Name, Last Name, and Phone number and then the output will be saved in a file named contacts.csv.
For example : John,Dawson,2102983187
Tried this but want to separate output with commas as it's on the example and it has to be in a loop.
#!/bin/bash
IFS=','
touch contacts.csv
echo "What's your contact's first name?"
read fname
echo "$fname" | grep '^[[:upper:]]\+[a-z]\{0,\}' >> contacts.csv
echo "What's your contact's last name?"
read lname
echo "$lname" | grep '^[[:upper:]]\+[a-z]\{0,\}' >> contacts.csv
echo "Whats your contact's phone number"
read phone
echo "$phone" | grep '[0-9]\{10\}$' >> contacts.csv
#!/bin/ksh
read fname?"What's your contact's first name? "
read lname?"What's your contact's last name? "
read phone?"What's your contact's phone number? "
[[ $fname =~ ^[[:upper:]][a-z]+$ ]] || { echo "$fname should be uppercase first char followed by lowercase chars" ; exit 1; }
[[ $lname =~ ^[[:upper:]][a-z]+$ ]] || { echo "$fname should be uppercase first char followed by lowercase chars" ; exit 2; }
[[ $phone =~ ^[[:digit:]]+$ ]] || { echo "$fname should be digits only" ; exit 3; }
echo "$fname,$lname,$phone" >> contacts.csv
Changing IFS isn't necessary. IFS=Input separator, and from your checks, I assume, that you don't want , in your input.
Read can provide a prompt, no need to use echo.
I would check all inputs first, and then write to output.
If you put the block between
while true; do
...
done
An empty input will stop the processing

New Employee bash script

I am new to bash scripting. I have a script that i am working on for a school project and its not working as expected. I keep receiving a error on my if then statements.
#!/bin/bash
echo –e “Would you like to add a new employee’s information? y/n \n”
read EMPLOYEE
if [ $EMPLOYEE = “y” –o $EMPLOYEE = “Y” ]
then
echo –e “Please enter employee’s first name  \c”
read FIRST
echo –e “Please enter employee’s last name  \c”
read LAST
echo –e “Please enter empolyee’s ID  \c”
read ID
echo –e “$FIRST\t$LAST\t$ID” >> database
fi
echo –e “Would you like to search for an employee? y/n \n”
read SEARCH
if [ $SEARCH = “y” –o $SEARCH = “Y” ]
then
echo –e “Enter the first name, last name or employee ID to search for.  \c”
read WORD
grep “$WORD” database
fi
With even a bash version 3 the following should work as you intended and be somehow shellitical correct ;-)
#!/bin/bash
printf "Would you like to add a new employee’s information? y/n \n"
read -r EMPLOYEE
if [ "$(tr '[:upper:]' '[:lower:]' <<<"$EMPLOYEE")" = "y" ]
then
printf "Please enter employee’s first name : \c"
read -r FIRST
printf "Please enter employee’s last name : \c"
read -r LAST
printf "Please enter empolyee’s ID : \c"
read -r ID
printf "%s\t%s\t%s" "$FIRST" "$LAST" "$ID" >> database
fi
printf "Would you like to search for an employee? y/n \n"
read -r SEARCH
if [ "$(tr '[:upper:]' '[:lower:]' <<<"$SEARCH")" = "y" ]
then
printf "Enter the first name, last name or employee ID to search for. : \c"
read -r WORD
grep "$WORD" database
fi
Notes on refactoring/repair:
Do not rely on echo -e in most cases printf works better and looks more like coding,
use read -rto mot mangle backslashes on input,
quote variables from input (with real ASCII quote characters), as the shell parser otherwise does funny things,
do not test against y and Y but simply lowercase the string received to only compare one variant.
Use some indent concept to track, and
use a shell linter as suggested by a commenter already (that one works nicely currently).
The above code does have no errors indicated in the above mentioned linter.
Small task for as exercise for the reader (thanks andlrc :)
Use lowercase variable names and I amend meaningful names
Enjoy the learning of the shell coding!

unix shell programming - checking for numbers and letters

I'm fairly new to Unix shell or bash programming.
I'm doing a project on an inventory program. I'm wondering if it is possible to check for numbers and letters within a function.
For example, I were to sell a hamburger, within the price I would only put numbers, if I were to input letters in it, how can i check that I have put letters instead of numbers in it?
Sorry if my English is bad, English is not my first language.
echo -n "Food :"
read food
echo -n "Price :"
read price
You could do it in multiple ways.
Using test with if condition:
if [ $var -eq $var 2> /dev/null ]
then
...
fi
OR
if [[ $var == +([0-9]) ]]
then
## its a number
fi
Using egrep with regex command like:
if [[ echo $var | egrep -q '^[0-9]+$' ]]
then
####...its a number...###
fi
It would be like:
read price
expression='^[0-9]+$'
if ! [[ $price =~ $expression ]] ; then
echo "Error: Please enter a number" >&2; exit 1
fi
Here, ^[0-9]+$ shows "starting(^) with a number[0-9] and continuing the same till the end($)
Hope that helps.
Allowing prices to have decimal points, this checks for valid prices:
re='^[0-9]+\.?[0-9]*$'
[[ $price =~ $re ]] && echo "Is Valid"
A more complete working example, which provides and error message for bad numbers, is:
read -p "Enter the food name: " food
re='^[0-9]+\.?[0-9]*$'
while true
do
read -p "Enter the price: " price
[[ $price =~ $re ]] && break
echo " You must enter a valid number"
echo " Please try again"
done
echo ""
echo "The price of $food is $price"
The following shows the above in action:
$ bash script.sh
Enter the food name: Hamburger
Enter the price: a lot
You must enter a valid number
Please try again
Enter the price: 1.9y
You must enter a valid number
Please try again
Enter the price: 0.99
The price of Hamburger is 0.99
How it works
The regular expression is ^[0-9]+\.?[0-9]*$. Let's look at it one piece at a time:
^ matches the beginning. This assures that no non-number characters precede the number
[0-9]+ matches one or more numbers
\.? matches the decimal point, if there is one.
[0-9]* matches numbers, if any, following the decimal point.
$ matches at the end of the string, assuring that there are no non-number characters following the number.

an issue with my dob sorting script

I am getting the error: line 34: #10#1001: syntax error: operand expected (error token is "#10#1001")
I have just changed
[! -f INPUT ] &
to
[ ! -f INPUT ] &&
and now i am getting the error
line 34: #10#1001: syntax error: operand expected (error token is "#10#1001")
when i run the script.
The script inputs users names, phones numbers and dob and then sorts the infomation and calculates their ages.
What could be causing this error as i cannot work out what operand it is demanding
#!/bin/bash
a=0
while [ $a -lt 2 ];
do
echo Please enter a first name
read firstName
echo Please enter last name
read lastName
echo Please enter phone number
read phoneNumber
echo Please enter date of birth - format dd/mm/yyyy
read dob
echo "$firstName,$lastName,$phoneNumber,$dob" >> userBirthdays.csv
echo If you would like to add another person press 1 or enter 2 to proceed
read a
done
INPUT=./userBirthdays.csv
OLDIFS=$IFS
IFS=","
[ ! -f INPUT ] && while read while read Name Surname Telephone DOB
do
birthMonth=${DOB:0:2}
birthDay=#10${DOB:3:2}
birthYear=${DOB:6:4}
currentDate=`date +%d/%m/%Y`
currentMonth=${currenDate:0:2}
currentDay=#10${currentDate:3:2}
currentYear=${currentDate:6:4}
if [[ "$currentMonth" -lt "$birthMonth" ]] || [[ "$currentMonth" -eq "$birthMonth" && "$((#10$currentDay))" -lt "$((#10$birthDay))" ]]
then
let Age=currentYear-birthYear-1
else
let Age=currentYear-birthYear
fi
echo "Name : $Name"
echo "Surname : $Surname"
echo "Telephone : $Telephone"
echo "DOB : $DOB"
echo "Age : $Age"
echo "##########################################"
done < $INPUT
IFS=$OLDIFS
echo $DATE
exit 0;
You have two mistakes on this line:
[ ! -f INPUT ] && while read while read Name Surname Telephone DOB
It should be:
[ -f ${INPUT} ] && while read Name Surname Telephone DOB
I recommend debugging your script with:
bash -x /path/to/birthdays.bash
This will print command traces before executing each command.
-lt comparison (and friends) are for integers, not strings. And you turn currendDay into a non-integer string by prepending #10 to it (you do it twice, by the way).
Your intentions here are not very clear. Do you want to compare strings? Then use < instead of -lt. Do you want currentDay to be a number? Then don't prepend #10 to its value (in both places you do it now).

Resources