Bash script for identifying users - bash

I think I may have approached this problem the wrong way and I could really use a hand here.
I'm trying to print a report to the screen using awk. I want to list the users logged in and their full names next to each user. The only way I could figure it out is below, but it only shows my own info. Can I add it into a loop somehow to achieve this or did I go about it completely wrong?
This is what I have:
echo "User name" "|" "Full name"
echo "--------------------------"
echo -n "$USER " ; awk -v user="$USER" -F":" 'user==$1{print$5}' /etc/passwd

The $USER variable just contains your username.
You can pipe the who command to get the list of logged in users.
echo "User name" "|" "Full name"
echo "--------------------------"
who | while read username rest; do
echo -n "$username " ; awk -v user="$username" -F":" 'user==$1{print$5}' /etc/passwd
done

Whenever you find yourself writing a loop in shell to process text, you have the wrong solution.
who | awk '
BEGIN { print "User name|Full name\n--------------------------" }
NR==FNR { name[$1] = $5; next }
{ print $1, name[$1] }
' FS=":" /etc/passwd FS=" " -
Shell is just an environment from which to call tools and it has a language to sequence those calls. The shell tool to process text is awk.

Related

Bash - creating a variable out of the printed ls

Im struggling with creating a bash script similiar to ps.
I just can't get it how bash works and how to make it work. Worst thing, it's first language that I don't even know how to start with and the pressure from college is making only things worse.
My plan is:
Create a while loop
Trough all the stuff of "ls /proc"
Create a variable out of found folder like "folder=$(awk '{print $i}')"
Printf the created variable and some stuff about if from /proc/i/status
End while loop if something happend to be not an integer.
And I just can't get it. Im facing tons of problems and googling them hard as usually when I start to learn a new language isn't helping to solve anything. I feel helpless with this task. I don't even know if my approuch to the problem is right :(
You don't need or want to parse ls output. Just loop over a wildcard directly.
for proc in /proc/*; do
pid=${proc#/proc/}
case $pid in *[!0-9]*) break;; esac
awk -v pid="pid" '{ printf "%i %s\n", pid, "stuff" }' $proc/status
done
You might want continue instead of break but the shell will alphabetize the hits when expanding the wildcard so the numeric entries will actually be grouped before other entries.
The parameter expansion ${variable#pattern} produces the value of variable with any leading match on pattern trimmed off. There is also ${variable%suffix} to trim a suffix matching a pattern, and a number of other simple string manipulation facilities.
You're not saying what exactly you want to extract from the process status, so let's say you want it's name and state
Borrowing from #tripleee answer, you could do:
#!/bin/sh
for proc in /proc/*
do
pid=${proc#/proc/}
case $pid in *[!0-9]*) continue;; esac
name=$(grep "Name" $proc/status | awk '{print $2$3}')
state=$(grep "State" $proc/status | awk '{print $2 " " $3}')
echo $proc $name $state | awk '{print $1 ", whose name is " $2 " is in state " $3 " " $4}'
done
Which would print something like:
/proc/98, whose name is kthrotld is in state I (idle)
/proc/9813, whose name is WebContent is in state S (sleeping)
/proc/99, whose name is acpi_thermal_pm is in state I (idle)
Or, if you want to get fancy, you could print with some color:
#!/bin/sh
for proc in /proc/*
do
pid=${proc#/proc/}
case $pid in *[!0-9]*) continue;; esac
name=$(grep "Name" $proc/status | awk '{print $2$3}')
state=$(grep "State" $proc/status | awk '{print $2 " " $3}')
echo $proc $name $state | awk '{print "\033[0;33m" $1 "\033[0;m, whose name is " "\033[0;32m" $2 "\033[0m is in state \033[0;34m" $3 " " $4 "\033[0m"}'
done
Which would output something like

echo "$var" prints blank space

I was basically trying to compare two files and as part of that I assigned the cksum of the file to a variable . But when I try to compare it, it did not work. I realized that when I tried to read the variable nothing gets printed out
The below commands worked just fine
s.joseph#VA-S-JOSEPH-900 /cygdrive/c/users/Anuprita
$ test=`cksum interface2 | awk -F" " '{ print $1 }'`
s.joseph#VA-S-JOSEPH-900 /cygdrive/c/users/Anuprita
$ echo "$test"
3021988741
But when these are part of a script and I try to echo $var, nothing gets printed
$ for i in `ls interface*`;
do chksum1=`cksum $i | awk -F" " '{ print "'$1'" }'`;
echo "$chksum1";
done
s.joseph#VA-S-JOSEPH-900 /cygdrive/c/users/Anuprita
$
I am using bash shell
Without assigning it to any variable, the output is as shown below
for i in interface*; do echo "interface=\"$i\""; cksum "$i"; done
interface="interface11"
4113442291 111 interface11
interface="interface17"
1275738681 111 interface17
interface="interface2"
3021988741 186 interface2
Looks like it is an issue only with bash on cygwin. The script seems to be working just fine on unix
for i in ls interface*; do chksum1=cksum $i | awk -F" " '{ print $1 }'; echo $i, $chksum1; done
interface1, 4294967295
interface2, 4294967295
Try this;
for i in ls interface*; do echo "interface=$i"; chksum1=$(cksum $i | awk -F" " '{ print "'$1'" }'); echo "$chksum1"; done
I like adding the echo statement to verify your getting what you think with the ls statement and the variable assignment should use $(cmd) or `cmd`
Cheers
What you have in your 2nd script:
print "'$1'"
is a completely different statement from what you have in your first one:
print $1
Think about it and ask yourself why you changed it and what it is you're trying to achieve. Also man awk and see g at http://cfajohnson.com/shell/cus-faq-2.html#Q24 for what print "'$1'" does.
Best I can tell without and provided sample input your script should be written:
for i in interface*; do chksum1=$(cksum "$i" | awk '{ print $1 }'); echo "$chksum1"; done

Check if read input is available in var

I try to list all Folders in /etc/nginx/html/.
I use this code:
folders=`for i in $(ls -d */ | grep -Ev "(backups)"); do echo ${i%%/}; done`
Now I get all folders with names non containing "backups".
Now I want to count the folder and save it into var. I use this code:
folders_count=( $folders )
echo ${#folders_count[#]}
It works. I get a list of all folders and I can count the folders.
Now I try to write a script that reads user input (or better, offers 1,2,3 choices, but I do not know how to do it) and install a script like Prestashop (as an example) into the folder the user has chosen if there are more than 1 folder.
Here is my code:
folders_count=( $folders )
echo ${#folders_count[#]}
echo
if [ ${#folders_count[#]} -gt 1 ]; then
echo "${info} Please choose a Website for Prestashop:" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
# for websites in $folders; do
# echo "${info} $folders" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
# echo "${info} $folders" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
# done
echo "$folders" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
#read websites_for_prestashop
read -e -i "$websites_for_prestashop" -p "Please enter your Website: " input
websites_for_prestashop="${input:-$websites_for_prestashop}"
if [ "$websites_for_prestashop" == "$folders" ]; then
echo "Website is $websites_for_prestashop"
else
echo "Website $websites_for_prestashop is not found"
fi
#echo "${info} Please choose a Website for Prestashop:" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
else
echo "nix"
fi
I dont know how I can make it work :/
Can anyone help me to fix it?
I would like to list the available folders. Then the user should be able to select in which folder he would like to install the script.
Folders:
[0] Folder 1
[1] Folder 2
[2] Folder 3
[3] Folder 4
....
Then a query will appear:
Please select an order for the installation:
The selection of the folder should then be stored in the variable read websites_for_prestashop
I do not know what your script is supposed to be doing. There are a bunch of lines commented out, the only assignment for websites_for_prestashop contains a reference to the variable itself and occurs after this variable is first used, and the script ultimately does nothing.
What I can tell you is that the way you extract filenames is not the right way to do it. Parsing the output of ls is not a good idea (see http://mywiki.wooledge.org/ParsingLs), and the way you do it will fail on any file with a name containing spaces, among other things.
This would be one way to do it:
declare -a folders=()
for f in */
do
[[ $f =~ backups ]] || folders+=("${f%/}")
done
echo "Folder count is: ${#folders[#]}"
Thank you for your help#
https://stackoverflow.com/users/2416376/olli-k
https://stackoverflow.com/users/7422249/fred
Solution is easy:
folders=`for i in $(ls -d */ | grep -Ev "(backups)"); do echo ${i%%/}; done`
echo "${info} Please choose a Website for Prestashop:" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
select websites_for_prestashop in $folders;
do
echo "You picked $websites_for_prestashop."
break
done

awk pattern matching - compare awk value with a input

I need some help writing a script that will compare the value(s) from running awk to user input.
i.e.:
cat employee.txt
100 Thomas Manager Sales $5,000
200 Jason Developer Technology $5,500
300 Sanjay Sysadmin Technology $7,000
400 Nisha Manager Marketing $9,500
500 Randy DBA Technology $6,000
EMPLOYERS=$(awk -F" " '{ print $2}' employee.txt)
echo "Enter the name of an employer: \c"
read employer
If/for/while employer is part of EMPLOYERS, echo a message.
Thanks in advance
or simply
...
awk -v emp=$employer '$2==emp{print "found"}' employee.txt
-v flag is for defining awk variables, here to pass shell value to script.
I would do it simpler:
echo "Enter the name of an employer: \c"
read employer
if [[ $(awk -F" " '{ print $2}' employee.txt | grep $employer) = $employer ]]
then
echo Found
fi

Check if a particular string is in a file bash

I want to write a script to check for duplicates
For example: I have a text file with information in the format of /etc/passwd
alice:x:1008:555:William Williams:/home/bill:/bin/bash
bob:x:1018:588:Bobs Boos:/home/bob:/bin/bash
bob:x:1019:528:Robt Ross:/home/bob:/bin/bash
james:x:1012:518:Tilly James:/home/bob:/bin/bash
I want to simply check if there are duplicate users and if there are, output the line to standard error. So in the example above since bob appears twice my output would simply generate something like:
Error duplicate user
bob:x:1018:588:Bobs Boos:/home/bob:/bin/bash
bob:x:1019:528:Robt Ross:/home/bob:/bin/bash
Right now I have a while loop that reads each line and stores each piece of information in a variable using awk -F that is delimited with ":". After storing my username I am not too sure on the best approach to check to see if it already exists.
Some parts of my code:
while read line; do
echo $line
user=`echo $line | awk -F : '{print $1}'`
match=`grep $user $1`($1 is the txtfile)
if [ $? -ne 0 ]; then
echo "Unique user"
else
echo "Not unique user"
then somehow grep those lines and output it
fi
done
The matching does not produce the right results
Suggestions?
instead of re-inventing the wheel, use the following tools:
cut to extract first field
sort and uniq to keep duplicated lines only.
cut -d : -f 1 | sort | uniq -d | while read i ; do
echo "error: duplicate user $i"
done
Sounds like a job for awk to me:
% awk -F':' '
/:/ {
count[$1] += 1
}
END {
for (user in count) {
if (count[user] > 1) {
print user " appears in the file " count[user] " times."
}
}
}
' /etc/passwd
A perl-proposal:
perl -F: -lanE 'push #{$h{$F[0]}},$_; END{for $k (keys %h){if(#{$h{$k}}>1){say "Error";say for #{$h{$k}}}}}' file

Resources