Bash: delete first line of stdin - bash

I've created a script for account creation that reads from a csv file, i do not need the first line in the csv as it has the titles for the colums, im trying to delete the first line using sed 1d $file, but it doesnt seem to work.
#!/bin/bash
FILE="applicants.csv"
sed 1d $FILE |while IFS=: read USERNAME PASSWORD SCHOOL PROGRAM STATUS; do
#------------------------------------------
groupadd -f $SCHOOL
useradd $USERNAME -p $PASSWORD -g $SCHOOL
if [ $? == 0 ]; then
echo
echo "Success! $USERNAME created"
grep $USERNAME /etc/passwd
echo
#------------------------------------------
else
echo "Failed to create account for $USERNAME"
fi
done < $FILE
here is the csv file
Full Name:DOB:School:Program:Status
JoseDavid:22-08-86:ACE:Bsc Computing:Unfinished
YasinAhmed:22-07-85:ACE:Bsc Networking:Complete
MohammedAli:21-04-84:ACE:Bsc Forensics:Complete
UtahKing:22-09-84:ACE:BSC IT:Unfinished
UsmanNaeem:21-09-75:ACE:BSC Computing:Complete
Here is a screenshot of the output
http://i.stack.imgur.com/R5zPN.jpg
is there anyway to skip the first line?

Try using tail -n +2 $FILE instead of sed.
You're reading from the unedited file with the redirect at the end: done < $FILE. Try changing that line to just done.

Related

How can I check if 'grep' doesn't have any output?

I need to check if the recipient username is in file /etc/passwd which contains all the users in my class, but I have tried a few different combinations of if statements and grep without success. The best I could come up with is below, but I don't think it's working properly.
My logic behind it is that if the grep is null, the user is invalid.
send_email()
{
message=
address=
attachment=
validuser=1
until [ "$validuser" = "0" ]
do
echo "Enter the email address: "
read address
if [ -z grep $address /etc/passwd ]
then
validuser=0
else
validuser=1
fi
echo -n "Enter the subject of the message: "
read message
echo ""
echo "Enter the file you want to attach: "
read attachment
mail -s "$message" "$address"<"$attachment"
done
press_enter
}
Just do a simple if like this:
if grep -q $address /etc/passwd
then
echo "OK";
else
echo "NOT OK";
fi
The -q option is used here just to make grep quiet (don't output...)
Use getent and check for grep's exit code. Avoid using /etc/passwd. Equivalent in the shell:
getent passwd | grep -q valid_user
echo $?
Output:
0
And:
getent passwd | grep -q invalid_user
echo $?
Output:
1
Your piece of code:
if [ -z grep $address /etc/passwd ]
You haven't saved the results of grep $address /etc/passwd in a variable. Before putting it in the if statement and then testing the variable to see if it is empty.
You can try it like this:
check_address=`grep $address /etc/passwd`
if [ -z "$check_address" ]
then
validuser=0
else
validuser=1
fi
The -z check is for variable strings, which your grep isn't giving. To give a value from your grep command, enclose it in $():
if [ -z $(grep $address /etc/passwd) ]
The easiest one will be this:
cat test123
# Output: 12345678
cat test123 | grep 123 >/dev/null && echo "grep result exist" || echo "grep result doesn't exist"
# Output: grep result exist
cat test123 | grep 999 >/dev/null && echo "grep result exist" || echo "grep result doesn't exist"
# Output: grep result doesn't exist
My problem was that the file I was trying to grep was a binary file. On windows, the first two characters in the file were little squares. On mac, the first two characters were question marks. When I used more or less on the file, I could see it was binary and when I used diff, it responded that the "Binary files foo.log and requirements.txt differ".
I used cat to display the contents of the file, highlighted and copied the text (minus the two question marks at the top, deleted the file, created a new file with touch and then used vi to paste the text back into the new file.
After that, grep worked fine.
Shorter:
until ! grep $address /etc/passwd ; do {
do_your_stuff
}

add specific string to a specific line at the end. -bash

I have a textfile(particulars.txt) which contains
personId,personName,employmentType
particulars.txt
1,jane,partTime
2,bob,fullTime
3,john,fullTime
How to do I make it such that if I key in the name of the worker, it will check whether that person is full time or part time worker and prompts the user to key in the salary and rewrite back to the file just for that person. I will explain in more details.
for example
Enter Name:jane
jane is a partTime staff
Enter Hourly Salary:10
so the textfile(particulars.txt) will now be
1,jane,partTime,10
2,bob,fullTime
3,johnfullTime
example two
Enter Name:bob
bob is a fullTime staff
Enter monthly Salary:1600
so the textfile(particulars.txt) will now be
1,jane,partTime,10
2,bob,fullTime,1600
3,john,fullTime
this is what I have
my code
#!/bin/bash
fileName="particulars.txt"
read -p "Enter name:" name
if grep -q $name $fileName; then
employmentType=$(grep $name $fileName | cut -d, -f4)
echo "$name is $employmentType" staff"
if [ $employmentType == "partTime" ]; then
echo "Enter hourly pay:"
read hourlyPay
#calculations for monthly salary(which I have not done)
elif [ $employmentType == "fullTime" ]; then
echo "Enter monthly salary:"
read monthlySalary
fi
else
echo "No record found"
fi
read -p "Press[Enter Key] to Contiune.." readEnterKey
I am only able to find which employment type does the person belongs to, but I am not sure of how/what should I do to add the salary at the end of the line just for that particular person. i have read up on sed , but I'm still confused on how to use sed to achieve my results and thus seeking help from you guys. Thanks in advance
Unless you need to do it in an interactive manner, you can say:
sed '/\bbob\b/{s/$/,1600/}' filename
This would add ,1600 to the line matching bob. Note that by specifying word boundaries \b, you'd ensure that the change is done only for bob, not abob or boba.
You can use the -i option to make the changes to the file in-place:
sed -i '/\bbob\b/{s/$/,1600/}' filename
EDIT: In order to use shell variable, use double quotes for the sed command:
sed "/\b$employeeName\b/{s/^$/,$monthlySalary/}" filename
I just modified your script.
#!/bin/bash
fileName="particulars.txt"
read -p "Enter name:" name
if grep -q $name $fileName; then
employmentType=$(grep $name $fileName | cut -d, -f3)
emp_name=$(grep $name $fileName | cut -d, -f2) # Getting emp name
emp_id=$(grep $name $fileName | cut -d, -f1) # Getting id
echo "$name is $employmentType staff"
if [ $employmentType == "partTime" ]; then
echo "Enter hourly pay:"
read hourlyPay
#calculations for monthly salary(which I have not done)
sed -i "s/^$emp_id.*$/&,$hourlyPay/g" $fileName # Modifying the file by using id.
elif [ $employmentType == "fullTime" ]; then
echo "Enter monthly salary:"
read monthlySalary
fi
else
echo "No record found"
fi
read -p "Press[Enter Key] to Contiune.." readEnterKey
I have added the below lines.
emp_id=$(grep $name $fileName | cut -d, -f1)
emp_name=$(grep $name $fileName | cut -d, -f2)
sed -i "s/^$emp_id.*$/&,$hourlyPay/g" $fileName

How to read from 2 files

I try to make a script to connect with MySQL.
Reading hosts from one file and the MySQL password from another file, but I have a problem.
When I try to execute the script it's returning me this error:
./do: line 15: syntax error: unexpected end of file
The code is like this:
#!/bin/bash
FILE=$1
INFO=$2
cat $FILE | while read HOST;
cat $INFO | while read INFO;do
DBS=`mysql -u root -p $INFO -h $HOST --connect_timeout=4 -Bse'show databases' | wc -l`
if [ "$DBS" -gt "0" ]; then
echo $HOST - mysql - $DBS >> log.sql
fi
sleep 0.1
done
Where is my mistake ?
Salut DragoČ™,
You can't use two while loops (even after you fix the syntax error) to read from two different files at the same time.
Instead, you can use paste to combine the two files first, then execute your loop:
#!/bin/bash
hostnames="$1"
passwords="$2"
while IFS=$'\t' read host password; do
dbs=$(mysql -u root -p "$password" -h "$host" --connect_timeout=4 -Bse'show databases' | wc -l)
[ $dbs -gt 0 ] && echo "$host - mysql - $dbs" >> log.sql
done <<<"$(paste "$hostnames" "$passwords")"
This script will correctly handle filenames with spaces, as well as hostnames and passwords containing spaces.

Reading line by line from a file in unix

I am a newbie in Unix I have a file which contains a list of file names. I am trying to copy every file in the same directory but with a different extension. Its not working. Can anyone tell me why my code is bellow csl_nl.sts is the file with name of other files?
#!/bin/csh
set files = ("csl_nl.sts")
foreach file ('cat files')
echo "Copying" $file "to" $file.cdc
cp $file $file.cdc
end
exit 0
this worked for me
#!/bin/csh
foreach file (`cat csl_nl.sts`)
set a=`echo $file | awk -F"." '{print $1}'`
echo "$a"
end
#!/bin/ksh
OLD_EXTN=old
NEW_EXTN=new
cat csl_nl.sts | while read line;
do
if [ ! -f $line];
then
echo $line does not exist ;
else
newfn=$(dirname $line)/$(basename $line .$OLD_EXTN).$NEW_EXTN
echo Copy from $line to $newfn
cp $line $newfn;
fi
done
see if this helps:
#!/bin/csh
set files = ("abc")
foreach file (`cat $files`)
set ext = ("cdc")
set file2 = "$file.$ext"
echo "Copying" $file "to" $file2;
cp $file $file2;
end
exit 0
Can't say I'm familiar with (t)csh, but, here's the obligatory bash example:
#!/bin/bash
for file in `cat csl_ns.tst`; do
echo $file " -> " $file.cdc
cp $file $file.cdc
done
Depends on the formatting of the input file, but that should work if they're seperated by whitespace or lines.

Deleting a PARTICULAR word from a file using shell script

Hi I am having a problem in deleting a particular set of words from a file using Shell script. Here goes my problem,
My file: group.dat
Sample lines
ADMIN
ADMINISTRATION
ADMINISTRATOR
My Script: groupdel.sh
#!/bin/sh
groupf="<pathtofile>/group.dat"
tmp="<pathtofile>/te"
delgrp()
{
echo "Enter the group to be deleted"
read gname
echo "-------------------"
for gn in `cat $groupf`
do
if [ "$gname" = "$gn" ]
then
sed -e "s/$gname//g" $groupf > $tmp&&mv $tmp $groupf
echo "deleted group"
cat $groupf
exit 1
fi
done
}
echo "Welcome to Group delete wizard"
delgrp
Output:
Enter the group to be deleted
ADMIN
deleted group
ISTRATION
ISTRATOR
Problem: My problem is I dont want the script to delete ADMINISTRATION or ADMINISTRATOR but to delete only ADMIN, any help how to achieve it.
Thanks in Advance
#!/bin/sh
groupf="<pathtofile>/group.dat"
tmp="<pathtofile>/te"
delgrp()
{
echo "Enter the group to be deleted"
read gname
echo "-------------------"
sed -e "/^$gname[[:blank:]]/d" "$groupf" > "$tmp" && mv "$tmp" "$groupf"
echo "deleted group $gname"
cat "$groupf"
return 0
}
echo "Welcome to Group delete wizard"
delgrp
Assuming that the group name is at the beginning of the line and there are other things on the line and you want to delete the whole line, use the regular expression and command as shown.
There's no need for a loop since sed will iterate over the lines of the file for free.
You should return from a function rather than exit from it. Zero means success. One indicates an error or failure.
Always quote variable names that contain filenames.
If the file is one group per line, and the group name is the only thing on the line, use anchors in your regular expression:
s/^$gname:.*//g
If you have Perl installed, you can probably simplify this a bit with something like this:
if grep -q "^${gname}:" $groupf ; then
perl -ni -e "print unless /^${gname}:/" $groupf
echo "Group deleted."
else
echo "No such group $gname."
fi
Or even
grep -v "^${gname}:" $groupf > $tmp && \
cp -f $tmp $groupf && rm -f $tmp
which will copy all lines except the matching one to the temporary file, and then copy the tempfile over the original file, replacing it.
Note that I suggest using a cp rather than a mv in order to retain the permissions of the original file; mv will result in the edited file having permissions set according to your umask with no concern for the original permissions.
So, for the complete script:
#!/bin/sh
groupf="<pathtofile>/group.dat"
tmp="<pathtofile>/te"
delgrp()
{
echo -n "Enter the group to be deleted: "
read gname
echo "-------------------"
if grep -q "^${gname}:" $groupf ; then
grep -v "^${gname}:" $groupf > $tmp
cp -f $tmp $groupf
rm -f $tmp
else
echo "No such group '$gname'"
fi
}
echo "Welcome to Group delete wizard"
delgrp
That should work reliably.
You can use \W to denote the start and end of a word, if they are separated properly:
sed -e "s/\(\W\)$gname\(\W\)/\1\2/g" $groupf > $tmp&&mv $tmp $groupf
Awk is a readable alternative to sed:
awk -v to_delete="$gname" -F: '$1 == to_delete {next} {print}'
Why you don't use sed ?
sed 's/^word$//g'
Also you can use regex to specify multiple words
sed 's/word1|word2//g'
I didn't try this, but this is what you need. Just take a look on Internet on the sed syntax.
Regards

Resources