skip to Main Content

I made this motd script:

#!/bin/bash

# Calulate avg CPU usage
usage=$((100-$(vmstat 1 2|tail -1|awk '{print $15}')))
aptlist=$(apt list --upgradable 2> /dev/null | sed 1d)

# Check if current usage isn't to high, else don't display the motd
if [[ ${usage%.*} -ge 95 ]];
then
  printf "motd disabled because current usage is %sn" "$usage"
else
  # The magic
  date=$(date)
#  usage=$(tail /proc/loadavg | awk '{print $1}')
  root_usage=$(df -h / | awk '/// {print $(NF-1)}')
#  memory_usage=$(free -m | grep Mem | awk '{print 100/$2*($2-$6+$5)}' | xargs printf "$1""%.2f")
  memory_usage=$(printf "%0.2f MB %d%%n" $(( $(sed -E '/^(MemTotal|MemFree|Cached|Buffers): *([0-9]*).*/'
'{s//2/;H;};$!d;x;s/[[:cntrl:]]//;s__/1024-_g;s_$_/1024_' /proc/meminfo) )) 
$(( $(sed -E '/^(MemTotal|MemFree|Cached|Buffers): *([0-9]*).*/'
'{s//2/;H;};$!d;x;s/[[:cntrl:]]//;s_([^n]+)n_@1@100*(1/1024-(_;s_n_/1024+_g;'
's_@([^@]+)@(.*)$_2/1024))/(1/1024)_' /proc/meminfo) )) | awk '{print $3}')
  users=$(users | wc -w)
  time=$(uptime | grep -ohe 'up .*' | sed 's/,/ hours/g' | awk '{ printf $2" "$3 }')
  processes=$(ps aux | wc -l)
  ip=$(ip addr | awk '/inet / { print $2 }' | sed -n '2{p;q}' | cut -d '/' -f1)
  ipv6=$(ip -6 addr |awk '{print $2}'| grep -v "^::" | grep "/" | head -n1 | cut -d '/' -f1)
  packages=$(dpkg-query -l | grep -c "^ii")
  updates=$(echo -n $aptlist | wc -l )
  secupdates=$(echo $aptlist | grep -c security )

  # The updates and secupdates var get's it's info thanks to this crontab/command
  # sudo apt-get -s dist-upgrade | grep "^Inst" | wc -l > /etc/update-motd.d/pkg.stats && apt-get -s dist-upgrade | grep "^Inst" | grep -i security | wc -l >> /etc/update-motd.d/pkg.stats
  # sudo crontab -l | { cat; echo "0 0 * * * apt-get -s dist-upgrade | grep "^Inst" | wc -l > /etc/update-motd.d/pkg.stats && apt-get -s dist-upgrade | grep "^Inst" | grep -i security | wc -l >> /etc/update-motd.d/pkg.stats"; } | crontab -
  # If you wish to not use crontab, switch the updates and secupdates comment's.

  # Header & motd
  printf "Welcome to %s (%s)" "$(lsb_release -s -d)" "$(uname -rm)"
  printf "n"

  echo "     __ __  __ _  __            _______"
  echo "    / //_/ / /(_)/ /__ ____    |_____|"
  echo "   / ,<   / // // //_// __     | │ │ |"
  echo "  / /| | / // // ,<  / /_/ /    |     |"
  echo " /_/ |_|/_//_//_/|_| ____/     ◯_____| "
  echo

  # System information
  echo "System information as of: $date"
  echo
#  printf "System Load:t%stSystem Uptime:t%sn" "$load" "$time" # Use this one if you prefer the linux proc avg
  printf "System Load:t%s%%tSystem Uptime:t%sn" "$usage" "$time"  # Overall processor usage
  printf "Memory Usage:t%stIP Address:t%sn" "$memory_usage" "$ip"
  if [[ $ipv6 == "" ]]
  then
    printf "Usage On /:t%stIPv6 Addres:tNo ipv6 address foundn" "$root_usage"
  else
    printf "Usage On /:t%stIPv6 Addres:t%sn" "$root_usage" "$ipv6"
  fi
  printf "Local Users:t%stProcesses:t%sn" "$users" "$processes"
  printf "Packages dpkg:t%stSession fortune: nn" "$packages"

  /usr/games/fortune

  # Check if there are updates
  echo
  if [[ $updates != 0 ]]
  then
    printf "%s updates can be installed immediately.n" "$updates"
    printf "%s of these updates are security updates.n" "$secupdates"
    printf "To see these additional updates run: apt list --upgradablenn"
  else
    printf "System is up-to-date!nn"
  fi

  # Check if a reboot is needed
  if [[ -f /var/run/reboot-required ]]
  then
    echo '*** System restart required ***'
  fi
fi
printf "%s" "$aptlist"

Now the execution time is 2 seconds b/c of these two commands:

usage=$((100-$(vmstat 1 2|tail -1|awk '{print $15}')))
aptlist=$(apt list --upgradable 2> /dev/null | sed 1d)

I tried to find a way to run both of the commands at the same time, so that it only takes a second (which would be amazing). Sadly using var1=cmd1 & var2=cmd2 doesn’t work and only the second get’s executed properly.

Anyone has a clue how to run two commands that go into each of their variables at the same time?
(i prefer to use the default tools in debian/Raspberry but if it’s impossible, i’m ok to install that package :))

Thank you for reading!

3

Answers


  1. One approach:

    • kick the 2x time consuming commands off in the background, making sure to redirect stdout/stderr to a pair of temp files
    • wait
    • process the 2x temp files and populate the 2x variables

    For example:

    (vmstat 1 2 | tail -1 | awk '{print $15}'    > tmp.1 2>&1) &
    (apt list --upgradable 2> /dev/null | sed 1d > tmp.2 2>&1) &
    
    wait
    
    usage=$((100 - $(cat tmp.1)))
    read -r aptlist < tmp.2
    

    NOTE: OP could add any necessary error checking after the wait and before the usage=$((...)); read -r aptlist ... commands

    Login or Signup to reply.
  2. use a dummy single-cycle for loop as a proxy for waiting :

     fgc; a0000=''; b0000=''; gdcmd='%n%n %D %T %s.%-N %n%n'
    
     gdate +"${gdcmd}"
    
     ( time ( for idx in 1; do {
    
           a0000=` lsof &` 
           b0000="$( df -h | mawk 'END { print }' & )" 
     } done
     
     echo "${b0000}n"
    
     printf '%s' "${a0000}" | wc5 ) )
     gdate +"${gdcmd}";
    
    
      09/04/22 16:24:30 1662323070.513516 
    
    
     //guest:@192.168.1.3/WD_4TB_RAID1/55_MyCloud_12T   
     11Ti   11Ti    0Bi   100% 11625431486 0  100% /Volumes/55_MyCloud_12T
    
    
      rows = 7330. | UTF8 chars = 1153070. | bytes      = 1153312.
    
     
     ( for idx in 1; do; { a0000=` lsof &` ; b0000= ; }; done; echo "${b0000}n"; )
     0.03s user 0.03s system 46% cpu 0.125 total
    
    
     09/04/22 16:24:30 1662323070.642752 
    

    As for ur commands, u can streamline them into

    vmstat 1 2 | mawk 'END { print 100 - $15 }'
    

    and

    apt list --upgradable 2>/dev/null | mawk '_{ exit }--_'
    

    UPDATE 1 : trying another approach

    a1=''; b1=''; tmp0=''
    echo " starting point :: ${a1}=${b1}=${tmp0}"
    
    gdcmd='%n %D %T %s.%-N %n'
    gdate +"${gdcmd}"; fgc
     
    ( time ( tmp0="$( for idx in 1; do 
    
        ( ( lsof  | mawk -F'^$' '$!NF="1" $_' ) & ) 
        ( ( df -h | mawk -F'^$' '$!NF="2" $_' ) & ) 
    
     done | gcat -)"
    
     a1="$( printf '%s' "${tmp0}" | mawk 'NF*=!_<NF' FS='^1' OFS= )"
     b1="$( printf '%s' "${tmp0}" | mawk 'NF*=!_<NF' FS='^2' OFS= )"
    
    printf '%s' "${a1}" | wc5; printf '%s' "${b1}" | wc5 ) )
    gdate +"${gdcmd}"
    
    starting point :: ==
    
    09/04/22 17:29:42 1662326982.253876 
    
    
    rows = 7394. | UTF8 chars = 1160393. | bytes = 1160635.
        
    rows =   14. | UTF8 chars =    1800. | bytes =    1800.
    
    
    ( tmp0= ; a1="$( printf '%s' "${tmp0}" | mawk 'NF*=!_<NF' FS='^1' OFS= )" ; )
    0.07s user 0.06s system 80% cpu 0.167 total
    
    09/04/22 17:29:42 1662326982.426079 
    
    Login or Signup to reply.
  3. As a variant on markp-fuso’s answer that avoids the need for temporary files by using process substitutions and automatic FD allocation (and is thus expected to work only with newer bash 4.x releases, or all bash 5.0+ releases):

    # start both vmstat and apt-list in the background
    exec {vmstat_fd}< <(vmstat 1 2 | tail -1 | awk '{print $15}')
    exec {aptlist_fd}< <(apt list --upgradable 2> /dev/null | sed 1d)
    
    # read one line of output from each
    read -r vmstat <&$vmstat_fd
    read -r aptlist <&$aptlist_fd
    
    # close both file descriptors
    exec {vmstat_fd}<&-
    exec {aptlist_fd}<&-
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search