Home > Mobile >  This script does its job halfway
This script does its job halfway

Time:05-31

For exercise I need to create a script that takes 2 parameters as input,

  • <n> an integer value
  • <path> the path to a directory

I need to create as many directories in path as there are users that have at least <n> processes running. The files have this formatting <pid>.txt and must contain ppid, time and command

#! /bin/bash

if [ $# -lt 2 ]

then

    echo "Hai inserito $#/2 parametri"

    echo "<n><path>"

    exit 1

fi



if [ "$1" -lt 0 ]

then

    echo "errore: Il valore inserito non può essere negativo" 

    exit 1

fi



if ! [ -d "$2" ]

then

    echo "errore: Il path indicato non è una directory" 

    exit 1

fi



OCCURRENCE=$1

PAT=$2



users=($(ps -Af | awk '{print $1}' | sort | uniq ))



for user in "${users[@]}"

do

    processes=$(ps -Af | awk -v user="$user" '$1==user'|wc -l)

    if [ "$processes" -gt "$OCCURRENCE" ]

    then

        mkdir $PAT/$user

        ps -Af | awk  -v user="$user" -v path="$PAT/$user" '$1=="user" {print $2,$7,$8 >>"$path/"$1".txt" }' 





    fi



done

The problem is that the files with the contents within the respective directories are not created, but the program only correctly creates the directories of the users that have more than <n> processes.

Is there any error in the awk command? Any better way to perform this task?

CodePudding user response:

Your first awk filter is right: $1==user. But the second is wrong: $1=="user" compares the first field with the literal string user, not with the value of variable user. As noted in comments you have a similar problem with "$path" that should be path (no $, no quotes).

Note also that you should filter out the first line of ps output, and that, different from bash redirections, > concatenates, no need for >>.

As you use awk here is another solution entirely based on awk (tested with GNU awk):

$ ps -Af | awk -v n="$1" -v p="$2" 'NR>1 {
    num[$1]  = 1
    proc[$1][$2 " " $7 " " $8]
  }
  END {
    for(u in num) {
      if(num[u] >= n) {
        d = p "/" u
        system("mkdir -p " d)
        for(e in proc[u])
          print e > d "/" u ".txt"
      }
    }
  }'

CodePudding user response:

This Shellcheck-clean Bash code demonstrates another way to perform the task:

#! /bin/bash -p

if (( $# < 2 )); then
    echo "Hai inserito $#/2 parametri" >&2
    echo "<n><path>" >&2
    exit 1
fi

min_proc_count=$1
output_dir=$2

if [[ -z $min_proc_count || $min_proc_count == *[^[:digit:]]* ]]; then
    echo 'errore: il valore inserito deve essere un numero positivo' >&2
    exit 1
fi

if [[ ! -d $output_dir ]]; then
    echo 'errore: Il path indicato non è una directory' >&2
    exit 1
fi

ps_output=$(ps -Af --no-headers)

# Get counts of processes for each user
declare -A user_proc_count
while read -r user _; do
    user_proc_count[$user]=$(( ${user_proc_count[$user]-0} 1 ))
done <<<"$ps_output"

# Generate per-process output files for users with enough processes
while read -r user pid ppid _ _ _ time cmd; do
    (( ${user_proc_count[$user]} < min_proc_count )) && continue
    dir=$output_dir/$user
    [[ -d $dir ]] || mkdir -v -- "$dir"
    printf '%d,%s,%s\n' "$ppid" "$time" "$cmd" >"$dir/${pid}.txt"
done <<<"$ps_output"

CodePudding user response:

Here's an awk-based solution that doesn't require any additional shell-level processing, and directly generate the necessary outputs.

Based on my amateur-hour understanding of ps, I think ps -Ao 'uid pid time command' may serve his/her purposes better.

For reasons truly unknown to me, i only could get it to work on gawk or mawk2, but not mawk-1 or nawk.

CODE

   ps -Ao 'uid pid time command' | 

   gawk -be '
   {
      528       ___[_=$!-__]
      528   sub(_ "[ \t] ","")
      528   sub("$",($-__)__,___[_])
     
    } END {
     1      sub("^[~][/]",ENVIRON["HOME"]"/",____)
            gsub("[/] ",                "/",____)
            sub("[/]$",          "",____)
            gsub(/\47/,"&\\&&",____)

     1      system(" mkdir -p \47" (____) "\47 2>/dev/null")
    35      for (_ in ___) {
    35          if ( _____ < (gsub(__, "&", ___[_]))) {
     5              printf("%s", ___[_]) > (____ "/" _".txt")
                }
             }
     }' _____='THRESHOLD_NUMBER' ____="${DESTINATION_PATH}" __='\n'

"${DESTINATION_PATH}" afterwards

total 800
-rw-r--r--  1 501 staff   11709 May 30 11:13 0.txt
-rw-r--r--  1 501 staff     509 May 30 11:13 205.txt
-rw-r--r--  1 501 staff     655 May 30 11:13 262.txt
-rw-r--r--  1 501 staff    1575 May 30 11:13 278.txt
-rw-r--r--  1 501 staff  791516 May 30 11:13 501.txt
 
 
             296 lines             791,175 utf8 (175 uc)          0.755 MB (      791515)  501.txt
             158 lines              11,708 utf8 (0. uc)           0.011 MB (       11708)  0.txt
               6 lines                 508 utf8 (0. uc)           0.000 MB (         508)  205.txt
              12 lines               1,574 utf8 (0. uc)           0.002 MB (        1574)  278.txt
               7 lines                 654 utf8 (0. uc)           0.001 MB (         654)  262.txt
 
==> 0.txt <==
    1   4:36.92 /sbin/launchd
    105   1:00.85 /usr/libexec/logd

==> 205.txt <==
  148   0:32.10 /usr/libexec/locationd
  286   0:00.56 /System/Library/PrivateFrameworks/GeoServices.framewor

==> 262.txt <==
  346   0:00.84 /usr/sbin/distnoted agent
  365   0:00.06 /System/Library/Frameworks/CoreMediaIO.framework/Versi

==> 278.txt <==
  113   0:00.46 /System/Library/PrivateFrameworks/MobileAccessoryUpdat
  376   0:00.83 /usr/sbin/distnoted agent

==> 501.txt <==
  184   0:01.64 /System/Library/CoreServices/loginwindow.app/Contents/
  426   0:22.44 /usr/sbin/distnoted agent
  • Related