I have to print information about the user with the name given as a parameter. For example let's say
./script1.sh John
should give me
John Doe (username) -last login-
I think I managed this, but I also have to check multiple parameters like
./script1.sh John Jane Etrjk
John Doe (username) -last login-
Jane Doe (username) -last login
Etrjk not found
and I do not know how to use multiple parameters in my script
this is my script so far (works for 1 parameter):
if [ -z "$1 ]
then
echo "no arguments"
exit
fi
var = $1
if grep -q "$1" /etc/passwd
then
echo "FOUND"
awk 'BEGIN {FS = ":" }; /'$1'/ {print $5,$1}' /etc/passwd
var2=$(awk 'BEGIN {FS = ":" }; /'$1'/ {print $1}' /etc/passwd
lastlog -u $var2 | awk 'NR==2 {print $4,$5,$6}'
else
echo "not found"
fi
You'll do:
for name in "$#"; do
...
done
The shell allows the shorhand for name do to iterate over the positional parameters. I prefer to be explicit about it.
The safe way to pass parameters into awk is with the -v option:
username=$(awk -v name="$name" 'BEGIN {FS = ":" }; $0 ~ name {print $1}' /etc/passwd)
I suggest you get into the habit of using meaningful variable names. It will help anyone (including you) who is reading your code.
Related
What I really want is, I have a file: example.txt
The file is structured this way: FirstName LastName UserID Grade
I have two options: If the Grade is greater than 5 I want a mail to the user via [UserID]:
Dear [FirstName] [LastName]!
On this subject, your grade is [Grade]!
The second option is: If the [Grade] is less than 5 I want a mail to the user via [UserID]:
Dear [FirstName] [LastName]!
On this subject, your grade was less than 5!
Using awk'{print $1}' etc.
Thanks in advance!
Try the following script file :
#!/bin/bash
your_grade_files="/path_to_file.txt"
while read p; do
FirstName=$(echo $p | awk -F' ' '{print $1}')
LastName=$(echo $p | awk -F' ' '{print $2}')
UserID=$(echo $p | awk -F' ' '{print $3}')
Grade=$(echo $p | awk -F' ' '{print $4}')
if [ "$Grade" -gt 5 ]
then
mail -s "Enter your subject here" $UserID <<< "Dear $FirstName $LastName! On this subject, your grade is [ $Grade ] "
else
mail -s "Enter your subject here" $UserID <<< "Dear $FirstName $LastName! On this subject, your grade was less than 5!"
fi
done < $your_grade_files
Based on your question , You ll need to read the contents of the file iteratively
As you parse the contents line by line you can apply the mail to be triggered , based on the Grade value
while read line; do
grade = $(echo $line | awk -F' ' '{print $4}')
userid = $(echo $line | awk -F' ' '{print $3}')
if [[ $grade -gt 5]] then
sendMail $userid $grade
done < file.txt
func sendMail(){
userid = $1
grade = $2
MESSAGE="[$] : Your Grade -- $2"
SUBJECT="SOME SUBJECT"
TOADDR="u#u.com"
FROM="DONOTREPLY"
echo $MESSAGE | mail -s "$SUBJECT" $TOADDR -f $FROM
}
You can further modify the code snippet based on your requirement
I have a students.txt (RollNo, Name, IDU, CGPA), If Roll number exists prompt the user to change the IDU and CGPA and update the same in the file named “Student.txt”
I made the following script:
#! /bin/bash
dispaly(){
awk -F ":" -v roll=$1 '{ if ( $1 == roll) {name = $2; print name; } }
END {if (name == "") print "not found" }' students.txt
}
echo "Enter the roll no."
read rno
if [ $rno -ge 1000 ] && [ $rno -le 9999 ]
then
dispaly $rno
# Now I have a valid $rno and want to update that line
else
echo Enter no between 1000 and 9999
fi
now I need help in taking user input for IDU and CGPA values and update the students.text file with that values against the record found.
In general "-" is used for standard input for awk e.g.
awk '{print($1)}' -
It's not clear to me exactly what you want here. Can't you use additional 'read' statements in the bash part of the script for input of the other 2 values?
first, I grep for roll
grep ^roll students.txt
if found then used awk to replace the records
awk -F : -v rno=$rno -v idu=$idu -v cgpa=$cgpa ' $1==rno { $3=idu;$4=cgpa} OFS=":" ' students.txt > tmp.txt && mv tmp.txt students.txt
eval: syntax error at line 1: `then' unexpected
Hi, I am having issues with this particular loop and couldn't find a solution to it, any ideas why?
getent passwd | cut -f1 -d":" | sort -n | uniq -c |\ while read x ; do [ -z "${x}" ] && break set - $x if [ $1 -gt 1 ]; then gids=`getent passwd |\ nawk -F: '($1 == n) { print $3 }' n=$2 | xargs` echo "Duplicate Group Name ($2): ${gids}" fi done
If you run the code through shellcheck and correct the errors which it shows (except for one problematic warning), the code will become:
getent passwd | cut -f1 -d":" | sort -n | uniq -c |
while read -r x ; do
[ -z "${x}" ] && break
set - $x
if [ "$1" -gt 1 ]; then
gids=$(getent passwd | nawk -F: '($1 == n) { print $3 }' n="$2" | xargs)
echo "Duplicate Group Name ($2): ${gids}"
fi
done
The code still seems to have issues, one of which is that it looks for duplicate user names but the print out claims that it found duplicate group names.
I would suggest replacing the above with:
getent passwd | awk -F: '{c[$1]++; uids[$1]=uids[$1]" "$3} END{for (name in c) if (c[name]>1) printf "Duplicate User Name (%s):%s\n",name, uids[name]}'
How the awk code works
In the output of getent passwd, the user name will be in field 1 and the user ID will be in field 3.
c[$1]++; uids[$1]=uids[$1]" "$3
This counts the number of times that user name $1 occurs and saves the count in array c. It also saves the user ID, $3, associated with each name in array uids.
END{for (name in c) if (c[name]>1) printf "Duplicate User Name (%s):%s\n",name, uids[name]}
After we have finished processing getent's output, this looks for user names for which the count is greater than 1 and prints the info.
Multiline version of suggested code
getent passwd | awk -F: '
{
c[$1]++
uids[$1] = uids[$1] " " $3
}
END{
for (name in c)
if (c[name]>1)
printf "Duplicate User Name (%s):%s\n", name, uids[name]
}'
I have a file called names.txt that holds a list of names. Some of these names do not correspond to names in /etc/passwd (5th field) and some do. For the names in the file that have users with the name I want to print their user name. For example if the name Bill Gates was in the names.txt file and this line is in /etc/passwd bgates:x:23246:879:Bill Gates:/co/bgates:/bin/bash I would print out "Bill Gates exists and has the username 'bgates'"
This is what I've been trying, but it just prints out the entire /etc/passwd file.
while read name; do
if cut -d: -f5 '/etc/passwd' | grep -q "$name"; then
userName=$(cat /etc/passwd | cut -d: -f6)
echo "$name exists and has the username $userName"
else
echo "no such person '$line'"
fi
done < names.txt
Thank you
Maybe something like this?
#!/bin/bash
#set -x
set -eu
set -o pipefail
function get_pwent_by_name
{
full_name="$1"
while read pwent
do
pw_full_name=$(echo "$pwent" | awk -F':' ' { print $5 }')
if echo "$pw_full_name" | egrep -iq "$full_name"
then
echo "$pwent"
break
fi
done < /etc/passwd
}
while read name
do
pwent=$(get_pwent_by_name "$name")
if [ "$pwent" != "" ]
then
userName=$(echo "$pwent" | awk -F':' ' { print $1 }')
echo "$name exists and has the username $userName"
else
echo "No such person as $name"
fi
done < names.txt
Do you accept to use awk to resolve your problem?
awk -F: 'NR==FNR{a[$5]=$1;next}
{print ($0 in a)?$0 " exists and has the username " a[$0]:"no such person " $0}' /etc/passwd names.txt
I have a directory full of files like this:
[Location]
state=California
city=Palo Alto
[Outlet]
id=23
manager=John Doe
I want to write a small script, that outputs one line for each file like this:
John Doe,Palo Alto
How do I do that? I suspect some grep and looping. So far I have:
#!/bin/bash
echo Manager,City > result.txt
for f in *.config
do
cat "$f" | grep manager= >> result.txt
cat "$f" | grep city= >> result.txt
done
but that's of course incomplete since grep returns the whole line on its own line and I only want the part after the first = sign.
echo Manager,City > result.txt
for f in *.config; do
manager=$(awk -F= '$1=="manager" {print $2}' "$f")
city=$( awk -F= '$1=="city" {print $2}' "$f")
echo "$manager,$city"
done >> result.txt
awk -F= uses an equal sign as the field separator, and then checks for the desired variables ($1) and prints their values ($2). $(cmd) captures the output of a command and yields strings that can be assigned to the two variables $manager and $city.
Similar to John Kugelman's answer but using grep.
echo Manager,City > result.txt
for file in *.config; do
name=$(grep -oP '(?<=manager\=).*' "$file")
location=$(grep -oP '(?<=city\=).*' "$file")
echo "$name,$location"
done >> result.txt
You can do this with a single awk command, as per the following transcript:
pax> cat 1.config
[Location]
state=California
city=Palo Alto
[Outlet]
id=23
manager=John Doe
pax> cat 2.config
[Location]
state=Western Australia
city=Perth
[Outlet]
id=24
manager=Pax Diablo
pax> awk '
/^city=/ {gsub (/^city=/, "", $0); city=$0}
/^manager=/{gsub(/^manager=/, "", $0); print $0 "," city}
' *.config
John Doe,Palo Alto
Pax Diablo,Perth
Note that this assumes the city comes before the manager, and that all files have both city and manager. If those assumptions are incorrect, the awk script becomes a little more complex but it's still doable.
In that case, it becomes something like:
awk '
FNR==1 {city = ""; mgr = ""}
/^city=/ {gsub (/^city=/, "", $0); city = $0}
/^manager=/ {gsub (/^manager=/, "", $0); mgr = $0}
{if (city!="" && mgr!=""){
print mgr "," city; city = ""; mgr = "";
}}
' *.config
What this does is to make the order irrelevant. It resets the city and manager variables to empty string at the start of each file and just stores them in the cases where it finds the relevant lines. After every line, if both are set, it prints and clears them.