an issue with my dob sorting script - bash

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).

Related

Is there any way to check if there is any input then contiue?

I am a newbie in bash programming. I need a bash script which can check if there is an input or not.If there is an input then continue to the second question, otherwise it will not continue unless it forces me to write the input (data). I wrote this script but is not working:
echo "Write buss no:"
read bussno
while [ true ] ; do
if [ -z $bussno ] ; then
echo "\Buss No. should be filled"
read bussno
else
echo "Write from date: "
read startdate
if [ -z $startdate ] ; then
echo "\start date should be filled"
read startdate
fi
done
Bash read command support timeout. You can set the timeout to zero:
From man bash:
-t timeout
Cause read to time out and return failure if a complete line of input
is not read within timeout seconds. timeout may be a decimal number
with a fractional portion following the decimal point. This option is
only effective if read is reading input from a terminal, pipe, or
other special file; it has no effect when reading from regular files.
If timeout is 0, read returns success if input is available on the
specified file descriptor, failure otherwise. The exit status is
greater than 128 if the timeout is exceeded.
Basically use bussno= ; read -t0 bussno instead of read bussno
There are ways, but you want to keep it simple, yes?
Maybe the logic you want is something like
while [[ -z "$bussno" ]]; do read -r -p "Please enter a business number: " bussno; done
while [[ -z "$startdate" ]]; do read -r -p "Please enter a start date: " startdate; done
This still leaves a lot to be desired in terms of data confirmation, though.
You can add a regex for that if you want, and some follow up confirmations.
For example, for the date,
valid_date='^[[:digit:]]{8}$'
msg="A valid start date is today or later as YYYYMMDD, e.g.: 20220823"
echo "$msg"
until [[ -n "$startdate" && $startdate =~ $valid_date ]]; do
read -p "Please enter a valid start date: " startdate
if date -d "$startdate" >/dev/null 2>&1 && # fail if invalid date
(( "$(date +'%Y%m%d')" <= "$startdate" )) # fail if in past
then break
else echo "'$startdate' is not a valid date."
echo "$msg"
startdate= # reset
fi
done
These still leave much to be desired, but it's a start.

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

shell script if else loop not working

Given the following programme which reads in user input twice
function search_grep
{
if [ "$2" == "" ];then
for x in "${title[#]}"
do
value=$(echo $x | grep "$1")
if [ "$value" != "" ];then
echo "$value"
fi
done
elif [ "$1" == "" ];then
hello="123"
echo "$hello"
fi
}
echo -n "Enter title : "
read book_title
echo -n "Enter author : "
read author
title=(CatchMe HappyDay)
search_grep $book_title $author
it works as expected when i enter followed by HappyDay HOWEVER
When i enter foo followed by , I would expect console output to be
123
instead I am getting
Can someone explain to me , the programme is not executing the second elif loop though second input is
In both of your cases cases, the following:
search_grep $book_title $author
expands to a call with a single argument. Hence, the "then" clause is activated. The reason is that an unquoted argument consisting of whitespace expands to nothing and disappears. That is the way of bash.
If you want to pass search_grep two arguments, then you need to quote the variables:
search_grep "$book_title" "$author"
As shown here, you might try using = instead of ==
Or for an empty string comparison try -z

What is wrong with my DOB Sorting script

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).

Resources