Modify the output of the command "last" - linux

I want to make a program in bash to display the output of last with this format:
username | number of sessions | duration of sessions | maximum session length
I already did the first two columns but don´t know how to do the rest.
This is the code I wrote for the username and number of sessions:
last |& tee last.txt
cut -d' ' -f1,2 last.txt > last1.txt
thanks

You can try with something like this. Its not perfect but very close :
#!/bin/bash
unique_users="$( last | awk ' {print $1} ' | sort | uniq | grep -v 'shutdown\|wtmp\|reboot' | awk 'NF' )"
for user in $unique_users
do
number_of_sessions="$( last $user | awk '{print $NF}' | grep '^(' | tr -d '()' | wc -l )"
total_mins="$( last $user | awk '{print $NF}' | grep '^(' | tr -d '()' | awk '{ split($1, t, ":"); print (t[1]*60+t[2]) }' | awk '{ sum+=$1}END{print sum/60}' )"
max_length="$( last $user | awk '{print $NF}' | grep '^(' | tr -d '()' | awk '{ split($1, t, ":"); print (t[1]*60+t[2]) }' | sort -rn | head -1 | awk '{ sum+=$1}END{print sum/60}')"
printf "$user | $number_of_sessions | $total_mins | $max_length\n"
done
Regards!

I'm assuming last output same as Mint19
owner tty7 :0 Sun Nov 17 06:18 gone - no logout
owner tty7 :0 Sun Nov 10 11:13 - crash (6+18:34)
owner tty7 :0 Thu Nov 7 14:10 - 11:11 (2+21:00)
owner pts/1 :0 Wed Nov 6 21:48 - 21:48 (00:00)
owner pts/1 :0 Wed Nov 6 21:37 - 21:40 (00:03)
The file is sorted by timestamp, and the 10th column contain the session duration: either (HH:MM), or (DAYS+HH:MM). Small awk will do the trick. Script only count terminated session - ignoring crashed/still running sessions.
Total is session time in minutes.
#! /usr/bin/awk -f
{
id=$1
if ( match($10, /\(([0-9]+)\+\)?([0-9][0-9]):([0-9][0-9])/, a) ) {
dur_min = a[1]*24*60 + a[3] * 60 + a[4] ;
s_count[id]++ ;
s_total[id] += dur_min
if ( dur_min > s_max[id] ) s_max[id] = dur_min
}
}
END {
print "ID", "Count", "Total(min)", "Max(min)"
for (id in s_count) {
print id, s_count[id], s_total[id], s_max[id]
} ;
}

Related

Shell script printf not printing variables

i'm new in stackoverflow, I’m trying to print something like that.
From: email#domain.com
To: rcpt#domain.com
Date: date
LOG_ID: ID
I’m reading the Postfix logs, which contains the following text:
Oct 28 10:42:48 host postfix/pickup[8779]: 4B0782A016E: uid=1000 from=<from#from.com>
Oct 28 10:42:48 host postfix/cleanup[14607]: 4B0782A016E: message-id=<20211028134248.4B0782A016E#mail.democloud.com>
Oct 28 10:42:48 host postfix/qmgr[2656]: 4B0782A016E: from=<from#from.com>, size=400, nrcpt=1 (queue active)
Oct 28 10:42:50 host postfix/smtp[14610]: 4B0782A016E: to=<rcpt#rcpt.com>, relay=gmail-smtp-in.l.google.com[172.217.192.26]:25, delay=1.7, delays=0/0/1.1/0.64, dsn=2.0.0, status=sent (250 2.0.0 OK 1635428569 jl7si2828702qvb.144 - gsmtp)
Oct 28 10:42:50 host postfix/qmgr[2656]: 4B0782A016E: removed
To perform the task I created the following shell script:
#!/bin/bash
if [ $# -ne 1 ] ; then
echo "
Ingresar cuenta de correo
Ej.: $0 rcpt#rcpt.com
"
exit 1
fi
RCPT="$1"
MAILOG="/var/log/mail.log"
STATS_DIR="/tmp"
echo -e "\n==== Detalle Total de Envios a <$1> ==== "
echo
QUEUEID=`grep -w "to=<${RCPT}>" ${MAILOG} | grep -E "status=(sent|deferred|bounced)" | awk -F"smtp" '{print $2}' | cut -d":" -f2 | sed -e s'/ //'g | sort | uniq`
for QID in ${QUEUEID} ; do
EMAIL=`grep ${QID} /var/log/mail.log | sed -r 's/^([^;]*;)[^;]*;/\1/' | awk 'BEGIN{FS=OFS=" "} {print $7}' | grep -w "from=" | tr -d , | grep -E -o "\b[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b"`
RCPT=`grep ${QID} /var/log/mail.log | sed -r 's/^([^;]*;)[^;]*;/\1/' | awk 'BEGIN{FS=OFS=" "} {print $7}' | grep -w "to=" | tr -d , | grep -E -o "\b[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b"`
DATE=`grep ${QID} /var/log/mail.log | sed -r 's/^([^;]*;)[^;]*;/\1/' | awk 'BEGIN{FS=OFS=" "} {print $1, $2,$3}'`
printf "From: $s\nDestinatario: $s\nFecha: $s\nLOG_ID: $s\n\n" "${EMAIL}" "${RCPT}" "${DATE}" "${QID}"
done
exit 0
My problem is running printf, the script output is empty.
What’s the problem? Can you help me improve the script, thank you.
Regards,

how to cut substring from linux command "who"

command who returns list of users logged to server
[admin#DB01ATK ~]$ who
adm_drodmann pts/3 2015-07-01 08:57 (10.129.12.77)
adm_ssmith pts/4 2015-07-01 02:11 (10.129.12.76)
adm_kholdman pts/2 2015-06-30 23:08 (10.129.12.45)
the point is to assign to variable, value of username($1) where terminal($2) is result from command
ps aux | grep screen
question asked question answered:
PTS=$(awk '{print $7}' <<< $(ps aux | grep screen) )
who | while read CMD;
do
res=$(awk '{print $2}' <<< "$CMD")
if [ "$res" = "$PTS" ]
then
echo "logged as $(awk '{print $1}' <<< "$CMD")"
fi
done;
:-)
As per your comment I expand my solution. You want to say:
ptw=$(ps aux | awk '/screen/ {print $7}')
while IFS=read -r user res _;
do
[ "$res" = "$PTS" ] && echo "logged as $user"
done < <(who)

Bash script variable output not working

I have a bash script that is parsing files containing information about processes running on a server. Everything works except the output.
Target output
tomcat7 Running Monitored 3025 18d 2h 16m 3.6% 0.0%
What it actually is outputing
0.0%2h 16m ing
Script portion doing the parsing and output
for SERVER in $SERVERS ; do
SYSTEM=$(sed -n '/System/{p; n;p; n;p; n;p; n;p; n;p}' $H_DIR/$SERVER.txt)
sed -n '/Process/{p; n;p; n;p; n;p; n; n;p; n;n;n; n;p; n; n;p}' $H_DIR/$SERVER.txt > $H_DIR/procs.txt
split --lines=7 $H_DIR/procs.txt $H_DIR/procs.txt.
for PROC in $H_DIR/procs.txt.?? ; do
PROCESS=$(cat $PROC | head -1 | tail -1 | cut -d "'" -f2)
STATUS=$(cat $PROC | head -2 | tail -1 | awk '{ print $NF }')
MONITOR=$(cat $PROC | head -3 | tail -1 | awk '{ print $NF }')
PID=$(cat $PROC | head -4 | tail -1 | awk '{ print $NF }')
UPTIME=$(cat $PROC | head -5 | tail -1 | awk '{ print substr($0, index($0, $2)) }')
PCPU=$(cat $PROC | head -6 | tail -1 | awk '{ print $NF }')
PMEM=$(cat $PROC | head -7 | tail -1 | awk '{ print $NF }')
echo $PROCESS $STATUS $MONITOR $PID $UPTIME $PCPU $PMEM
done
rm -f $H_DIR/procs.*
rm -f $H_DIR/$SERVER.txt
done
raw file being parse
Process 'tomcat7'
status Running
monitoring status Monitored
pid 3025
uptime 18d 2h 30m
memory percent 3.6%
cpu percent 0.0%
On a hunch - your input files have the DOS carriage return line feed combination.
I added that to your file and got the same results you did.
See this question for how to remove the carriage return:
Remove carriage return in Unix
Using the suggested tr -d '\r' method for removing carriage return (and might as well remove single quotes at the same time) you could do something like this:
echo $(tr -d "\r\'" < $PROC | awk 'NR==5{print substr($0,index($0,$2))}{print $NF}')
or if you need each variable assigned then something like this
VARS=$(tr -d "\r\'" < $PROC | awk 'NR==5{print substr($0,index($0,$2))}{print $NF}')
read PROCESS STATUS MONITOR PID UPTIME PCPU PMEM <<<$VARS
echo $PROCESS $STATUS $MONITOR $PID $UPTIME $PCPU $PMEM
Either way, output is
tomcat7 Running Monitored 3025 18d 2h 30m 30m 3.6% 0.0%

How to get the five last created users in order

How do I get the five last created users in order?
I can sort them by userId with this command but is there a file where you can see the date when the user is created?
tail -5 /etc/passwd | sort -r | grep '/home' | cut -d: -f1
You can look at the files in the system and sort the users based on the least recently modified files they own:
find /home | xargs -n 1 -I {} stat -c '%Y %U' "{}" | \
awk '$1 < d[$2] || !d[$2] { d[$2]=$1 } \
END{ for (u in d) { print d[u], u } }' | \
sort -n -k1

bash store output as a variable

grep -A 26 "some text" somefile.txt |
awk '/other text/ { gsub(/M/, " "); print $4 }' |
sort -n -r | uniq | head -1
will return the largest in a list pulled from a large text file, but how do I store the output as a variable?
Use command substitution:
my_var=$(grep -A 26 "some text" somefile.txt |
awk '/other text/ { gsub(/M/, " "); print $4 }' |
sort -n -r | uniq | head -n1)
Also, for portability, I would suggest always using -n1 for the argument of head. I've come across a couple of incarnations of it where using -1 doesn't work.
For unnested cases back quotes will work too:
variable=`grep -A 26 "some text" somefile.txt |
awk '/other text/ { gsub(/M/, " "); print $4 }' |
sort -nru | head -1`
I'd suggest
variable_name=$(grep -A 26 "some text" somefile.txt |
awk '/other text/ { gsub(/M/, " "); print $4 }' |
sort -nru | head -1)

Resources