grep function not working - bash

what am I doing wrong in the code below?
I am replacing the salary data within the text file, but the Telephone number field (the 3rd column) is being updated instead of the salary field (the 5th column) which is 0.
In the example below, the calculated salary for Ruben is 500.
My Desired output is:
Ruben,1223,97707001,Salaried,500
But instead, I get this (replacing zero between 9770 and 7001 with 535):
Ruben,1223,9775007001,Salaried,0
payroll_employee()
{
echo
echo "[Option: $input]"
echo "Enter Payroll of an employee "
echo
echo -en "Enter employee name: "
read Name
#Retrieve current entry into individual fields
line=`grep -i "$Name" $PAYROLL`
Name=`echo $line | cut -d "," -f1`
EmployeeID=`echo $line | cut -d "," -f2`
EmployeeHP=`echo $line | cut -d "," -f3`
EmployeeType=`echo $line | cut -d "," -f4`
Salary=`echo $line | cut -d "," -f5`
#Check if entry exist in records
if [ `count_lines "^${Name},"` -eq 0 ]
then
echo "Error: This particular record does not exist!!"
else
echo "$Name is ${EmployeeType} employee."
if [ "$EmployeeType" = "Salaried" ]
then
echo $EmployeeType
echo -en "Enter Weekly Salary:"
read swages
if [ -z $swages ]
then
swages=$Salary
else
grep -vi "$Name" $PAYROLL > tmpfile #Perform updating to salary field entry
grep -x "$line" $PAYROLL | sed -e "s/$Salary/$swages/" >> tmpfile
mv tmpfile $PAYROLL
echo "$Name's weekly payroll has been updated to \$$swages!!"
fi
echo
}
Sample code:
update_employee()
{
echo
echo "[Option: $input]"
echo "Updating employee record... "
echo "Please enter the name of the employee to update: "
echo -en "[1]Name: "
read update_name
#Retrieve current entry into individual fields
line=`grep -i "$update_name" $PAYROLL`
oldname=`echo $line | cut -d "," -f1`
oldjob=`echo $line | cut -d "," -f2`
olddept=`echo $line | cut -d "," -f3`
oldsal=`echo $line | cut -d "," -f4`
#Check if entry to update exist in records
if [ `count_lines "^${update_name},"` -eq 0 ]
then
echo "Error: This particular record does not exist!!"
else
while [ "$choice" != "6" ]
do
update_menu #Display update menu for user input,allows update of individual field or all at once
read update_choice
case $update_choice in
"1") echo -en "Please enter employee's new name: "
read new_name
if [ -z $new_name ]
then
new_name=$oldname
elif [ `count_lines "^${new_name},"` -ne 0 ] #Check if name already exist in records
then
echo "Error: Employee [$new_name] already exist in records!"
else
grep -vi "$oldname" $PAYROLL > tmpfile #Perform updating to name field entry
grep -x "$line" $PAYROLL | sed -e "s/$oldname/$new_name/" >> tmpfile
mv tmpfile $PAYROLL
echo "Employee's name $oldname has been updated to [$new_name]!!"
fi
break
;; }
All I changed was add one more column.
Salary=`echo $line | cut -d "," -f5`

payroll_employee()
{
echo
echo "[Option: $input]"
echo "Enter Payroll of an employee "
echo
echo -en "Enter employee name: "
read Name
#Retrieve current entry into individual fields
if [ $(grep -ciw "$Name" $PAYROLL) -eq 0 ]
then
echo "No matches found in $PAYROLL";
else
line=$(grep -iw "$Name" $PAYROLL);
Name=$(echo $line | awk -F "," print $1);
EmployeeID=$(echo $line | awk -F "," print $2);
EmployeeHP=$(echo $line | awk -F "," print $3);
EmployeeType=$(echo $line | awk -F "," print $4);
Salary=$(echo $line | awk -F "," print $5);
fi
if [ "$EmployeeType" == "Salaried" ]
then
echo $EmployeeType
echo -en "Enter Weekly Salary:"
read swages
if [ -z $swages ]
then
swages=$Salary
else
sed "/$Name/d" $PAYROLL
echo "$Name $EmployeeID $EmployeeHP $EmployeeType $swages" >> $PAYROLL;
echo "$Name's weekly payroll has been updated to \$$swages!!"
fi
echo
}
I Prefer use of AWK for delimination
also you can delete line using
sed "/$Name/d" $PAYROLL
Why to store it in other file using grep -vi and rename back and replace with original (Waste of memory & resources)
also "`" backtick should be replaced with new method of using $(..)
Also one make sure when you match strings use == sign
also in grep use -w also just to make sure that you select proper complete string
Ruben baruben rubenner all will be searched in grep if -w is not given

Seems like you are replacing every occurrence of the string $Salary in the payroll line, so if salary is 100 and the employee ID number is 2100, it will be replaced.
Instead of using sed at the end, you would probably be better off generating the output using printf and building the fields up that way.
Something like:
printf "%s,%s,%s,%s,%s\n" $Name $EmployeeID $EmployeeHP $EmployeeType $swages >> tmpfile
EDIT: You should fix the = to == as pointed out in the comments.
Also, to illustrate what I think is happening:
line="ABC,5100,DEF,100"
Salary=100
echo $line | sed -e s/${Salary}/XXX/
ABC,5XXX,DEF,100
If you "anchor" the query by putting a $ at the end of the search string, it will only match the last value.
echo $line | sed -e s/${Salary}$/XXX/
ABC,5100,DEF,XXX
Add some echo statements in your code to check the status of variables....

Related

String comparison from nested for returns always false

The main issue is that i try to parse ls to do a mock "Compare directories" but when i do so since i use nested fors i cant properly compare the results from it since the comparison of two filenames/strings even if they are the same it always returns false
I tried erasing the white characters but no results.
var1=$(ls -l $1 | grep -v ^d | tail -n +2 | tr -s " "| cut -d " " -f 9)
var2=$(ls -l $2 | grep -v ^d | tail -n +2 | tr -s " "| cut -d " " -f 9)
for i in $var1 ; do
i=$(printf "$i" | tr -d '[:space:]')
flag=0
var3=$(ls -l $1 | grep -v ^d | tail -n +2 | tr -s " " | grep $i | cut -d " " -f 5)
for j in $var2 ; do
j=$(printf $j | tr -d '[:space:]')
var4=$(ls -l $2 | grep -v ^d | tail -n +2 | tr -s " " | grep $j | cut -d " " -f 5)
if [ "$i" == "$j" ] ; then
if [ "$var3" != "$var4" ] ; then
flag=1
fi
else
flag=1
fi
done
if [ $flag -eq 1 ] ; then
printf "$i file does not exist on the $2 catalog\n"
printf "It 's size is :$var3 \n"
let Sum=$Sum+$var3
fi
done
This is not a string comparison problem, it's a logic problem.
I wrote you a MCVE that demonstrates the same problem with less code and fewer dependencies:
flag=0
target="hello"
for candidate in "hello" "world"
do
if [ "$target" != "$candidate" ]
then
flag=1
fi
done
if [ "$flag" -eq 1 ]
then
echo "The string was not found"
fi
This prints The string was not found every time, just like your script, even though it's clearly there.
The problem here is that the script requires that ALL files match. It should only require that ANY file matches. The easiest way to fix this is to:
Set flag=1 when a MATCH is found (not a mismatch)
Make flag=1 signify that a match was found (rather than no match was found)
Here's the version which correctly finds the string:
flag=0
target="hello"
for candidate in "hello" "world"
do
if [ "$target" = "$candidate" ]
then
flag=1
fi
done
if [ "$flag" -eq 1 ]
then
echo "The string was found"
else
echo "The string was not found"
fi

Unix - How do I have my shell script process more than one file from the command line?

I'm trying to modify an existing script I have to take up to three text files and transform them. Currently the script will only transform the text from one file. Here's the existing script I have:
if [ $# -eq 1 ]
then
if [ -f $1 ]
then
name="My Name"
echo $name
date
starting_data=$1
sed '/^id/ d' $starting_data > raw_data3
sed 's/-//g' raw_data3 > raw_data4
cut -f1 -d, raw_data4 > cutfile1.col1
cut -f2 -d, raw_data4 > cutfile1.col2
cut -f3 -d, raw_data4 > cutfile1.col3
sed 's/$/:/' cutfile1.col2 > last
sed 's/^ //' last > last2
sed 's/^ //' cutfile1.col3 > first
paste -d\ first last2 cutfile1.col1 > final
cat final
else
echo "$1 cannot be found."
fi
else
echo "Please enter a filename."
fi
All those temp files are unnecessary. awk can do all of what sed and cut can do, so this should be what you want (pending the output field separator question)
if [ $# -eq 0 ]; then
echo "usage: $0 file ..."
exit 1
fi
for file in "$#"; do
if ! [ -f "$file" ]; then
echo "file not found: $file"
continue
fi
name="My Name"
echo "$name"
date
awk -F, -v OFS=" " '
/^id/ {next}
{
gsub(/-/, "")
sub(/^ /, "", $2)
sub(/^ /, "", $3)
print $3, $2 ":", $1
}
' "$file" > final
cat final
done
Note all my double quotes: those are required.

compare 2 values within a while read loop, one from stdout and one from file

I have a while read line loop where i am assigning $user and $quota twhich are coming from stdout but i have also a file from another server where i am checking if $user is existing in this file, which is also containing the $user's quota.
I need to compare the $quota value which i am getting in stdout with the value within the file.
example:
zmsoap -z GetQuotaUsageRequest -v -u https://$sourceserver:7071/service/admin/soap/ |awk {'print $4" "$5'} | cut -d'"' -f2,4 | sed -r 's/["]+/ /g' | while read line
do {
user1=`echo $line|cut -f1 -d " "`
quota1=`echo $line|cut -f2 -d " "`
echo "$user1 has $quota1 on $sourceserver"
if grep -q "$user1" "$allremotequotasnew"; then
echo "OK: $user1 is EXISTING on $destserver"
else
echo "ERROR: $user1 NOT FOUND on $destserver" && echo "Creating $user1 on $destserver now..."
fi
}
done
any ideas? thanksa lot in advance
The file looks like: user33 quota and i need to check if $user is existing in the file, and if so, then also cut out it's quota
You can solve this question by the following script clips.
grep "$user1" "$allremotequotasnew" > /dev/null
if [ $? -eq 0 ];then
echo "OK: $user1 is EXISTING on $destserver"
dest_line=`grep "$user1" "$allremotequotasnew"`
dest_user=`echo $dest_line|cut -f1 -d " "`
dest_quota=`echo $dest_line|cut -f2 -d " "`
else
echo "ERROR: $user1 NOT FOUND on $destserver"
fi
dest_user and dest_quota are what you want to get from file.

Command not found error

I've received an error command not found not sure what is wrong.
i think there is a problem with my code. i need user to enter the pay.
first user enter the ID, then the program will find the person with that ID.
then program will find the type of employee he is [salaried, or hourly]
then from there it will goes to if [$type="Salaried"] or' Hourly' code and
prompt user to key in the respective data
please advise how do i go about doing it?
payroll()
{
line=`grep -i "^${update_empID}," $data`
empID=`echo $line | cut -d "," -f1`
name=`echo $line | cut -d "," -f2`
job=`echo $line | cut -d "," -f3`
phone=`echo $line | cut -d "," -f4`
type=`echo $line | cut -d "," -f5`
clear
echo -e "Enter the pay"
echo -en "Enter ID: "
read empid_search
#Check if particular entry to search for existed to perform deletion
if [ `count_lines "^${empid_search},"` -eq 0 ]
then
echo "Error: This particular record does not exist!!"
else
echo "Please verify update of this employee's record: " #Prompt for confirmation of employee details
echo
echo "Employee's Details: "
locate_lines "^${empid_search}," #Find location of the entry
if [$type="Salaried"]
then
echo "$name is a Salaried"
echo "Enter Salary :"
read salary
echo "${empID},${name},${job},${phone},${Type},${salary}" >> tmpfile ; mv tmpfile $data
echo " particulars has been updated!!"
fi
else
echo "f"
fi
}
TEXT FILE
3,Frak,IT,9765753,Salaried
1,May,CEO,9789292,Salaried
5,Samy,Sales user,92221312,Commission
2,Orange,cleaner,935233233,Hourly
error:
line 371: [=Salaried]: command not found
This is the problem line:
if [$type="Salaried"]
You need to have spaces while comparing values in [ and ]:
if [ "$type" = "Salaried" ]

Remove one directory component from path (string manipulation)

I'm looking for the easiest and most readable way to remove a field from a path. So for example, I have /this/is/my/complicated/path/here, and I would like to remove the 5th field ("/complicated") from the string, using bash commands, so that it becomes /this/is/my/path.
I could do this with
echo "/this/is/my/complicated/path/here" | cut -d/ -f-4
echo "/"
echo "/this/is/my/complicated/path/here" | cut -d/ -f6-
but I would like this done in just one easy command, something that would like
echo "/this/is/my/complicated/path" | tee >(cut -d/ -f-4) >(cut -d/ -f6-)
except that this doesn't work.
With cut, you can specify a comma separated list of fields to print:
$ echo "/this/is/my/complicated/path/here" | cut -d/ -f-4,6-
/this/is/my/path/here
So, it's not really necessary to use two commands.
How about using sed?
$ echo "/this/is/my/complicated/path/here" | sed -e "s%complicated/%%"
/this/is/my/path/here
This removes the 5th path element
echo "/this/is/my/complicated/path/here" |
perl -F/ -lane 'splice #F,4,1; print join("/", #F)'
just bash
IFS=/ read -a dirs <<< "/this/is/my/complicated/path/here"
newpath=$(IFS=/; echo "${dirs[*]:0:4} ${dirs[*]:5}")
Anything wrong with a bash script?
#!/bin/bash
if [ -z "$1" ]; then
us=$(echo $0 | sed "s/^\.\///") # Get rid of a starting ./
echo " "Usage: $us StringToParse [delimiterChar] [start] [end]
echo StringToParse: string to remove something from. Required
echo delimiterChar: Character to mark the columns "(default '/')"
echo " "start: starting column to cut "(default 5)"
echo " "end: last column to cut "(default 5)"
exit
fi
# Parse the parameters
theString=$1
if [ -z "$2" ]; then
delim=/
start=4
end=6
else
delim=$2
if [ -z "$3" ]; then
start=4
end=6
else
start=`expr $3 - 1`
if [ -z "$4" ]; then
end=6
else
end=`expr $4 + 1`
fi
fi
fi
result=`echo $theString | cut -d$delim -f-$start`
result=$result$delim
final=`echo $theString | cut -d$delim -f$end-`
result=$result$final
echo $result

Resources