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
Related
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.
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've this data :
cat >data1.txt <<'EOF'
2020-01-27-06-00;/dev/hd1;100;/
2020-01-27-12-00;/dev/hd1;100;/
2020-01-27-18-00;/dev/hd1;100;/
2020-01-27-06-00;/dev/hd2;200;/usr
2020-01-27-12-00;/dev/hd2;200;/usr
2020-01-27-18-00;/dev/hd2;200;/usr
EOF
cat >data2.txt <<'EOF'
2020-02-27-06-00;/dev/hd1;120;/
2020-02-27-12-00;/dev/hd1;120;/
2020-02-27-18-00;/dev/hd1;120;/
2020-02-27-06-00;/dev/hd2;230;/usr
2020-02-27-12-00;/dev/hd2;230;/usr
2020-02-27-18-00;/dev/hd2;230;/usr
EOF
cat >data3.txt <<'EOF'
2020-03-27-06-00;/dev/hd1;130;/
2020-03-27-12-00;/dev/hd1;130;/
2020-03-27-18-00;/dev/hd1;130;/
2020-03-27-06-00;/dev/hd2;240;/usr
2020-03-27-12-00;/dev/hd2;240;/usr
2020-03-27-18-00;/dev/hd2;240;/usr
EOF
I would like to create a .txt file for each filesystem ( so hd1.txt, hd2.txt, hd3.txt and hd4.txt ) and put in each .txt file the sum of the value from each FS from each dataX.txt. I've some difficulties to explain in english what I want, so here an example of the result wanted
Expected content for the output file hd1.txt:
2020-01;/dev/hd1;300;/
2020-02;/dev/hd1;360;/
2020-03;/dev/hd1;390:/
Expected content for the file hd2.txt:
2020-01;/dev/hd2;600;/usr
2020-02;/dev/hd2;690;/usr
2020-03;/dev/hd2;720;/usr
The implementation I've currently tried:
for i in $(cat *.txt | awk -F';' '{print $2}' | cut -d '/' -f3| uniq)
do
cat *.txt | grep -w $i | awk -F';' -v date="$(cat *.txt | awk -F';' '{print $1}' | cut -d'-' -f-2 | uniq )" '{sum+=$3} END {print date";"$2";"sum}' >> $i
done
But it doesn't works...
Can you show me how to do that ?
Because the format seems to be so constant, you can delimit the input with multiple separators and parse it easily in awk:
awk -v FS='[;-/]' '
prev != $9 {
if (length(output)) {
print output >> fileoutput
}
prev = $9
sum = 0
}
{
sum += $9
output = sprintf("%s-%s;/%s/%s;%d;/%s", $1, $2, $7, $8, sum, $11)
fileoutput = $8 ".txt"
}
END {
print output >> fileoutput
}
' *.txt
Tested on repl generates:
+ cat hd1.txt
2020-01;/dev/hd1;300;/
2020-02;/dev/hd1;360;/
2020-03;/dev/hd1;390;/
+ cat hd2.txt
2020-01;/dev/hd2;600;/usr
2020-02;/dev/hd2;690;/usr
2020-03;/dev/hd2;720;/usr
Alternatively, you could -v FS=';' and use split to split first and second column to extract the year and month and the hdX number.
If you seek a bash solution, I suggest you invert the loops - first iterate over files, then over identifiers in second column.
for file in *.txt; do
prev=
output=
while IFS=';' read -r date dev num path; do
hd=$(basename "$dev")
if [[ "$hd" != "${prev:-}" ]]; then
if ((${#output})); then
printf "%s\n" "$output" >> "$fileoutput"
fi
sum=0
prev="$hd"
fi
sum=$((sum + num))
output=$(
printf "%s;%s;%d;%s" \
"$(cut -d'-' -f1-2 <<<"$date")" \
"$dev" "$sum" "$path"
)
fileoutput="${hd}.txt"
done < "$file"
printf "%s\n" "$output" >> "$fileoutput"
done
You could also almost translate awk to bash 1:1 by doing IFS='-;/' in while read loop.
i have this bash script here that i'm trying to modify to check if there is only one root id, is it vulnerable and currently, this script only checks if there is a duplicate uid and display the users that shares the same uid. Thanks in advance! :)
Bash Script:
#!/bin/bash
/bin/cat /etc/passwd| /bin/cut -f3 -d":" | /bin/sort -n | /usr/bin/uniq-c | while
read x ; do
[ -z "${x}" ] && break
set -$x
if [ $1 -gt1 ]; then
users=`/bin/gawk -F: '($3 == n) { print $1 }' n=$2 /etc/passwd| /usr/bin/xargs`
echo "Duplicate UID ($2): ${users}"
fi
done
Expected Output:
Audit criteria: There is only one root id
Vulnerability: Yes
Details: See below
root:!:0:0::/:/usr/bin/bash
jdoe:*:0:1:John Doe:/home/jdoe:/usr/bin/bash
You can simplify your script greatly because all you are looking for is user id 0, which is root:
#!/bin/bash
root_count=$(cut -f3 -d":" /etc/passwd | grep -wc 0)
if [[ $root_count > 1 ]]; then
users=$(awk -F: '($3 == 0) { print $1 }' /etc/passwd | xargs)
echo "Duplicate roots: ${users}"
fi
You can use awk to find that out:
if ! awk -F: '$3==0{c++}END{exit !(c<2)}' /etc/passwd ; then
echo "More than one user with uid 0"
fi
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]
}'