-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathprocstat.sh
executable file
·254 lines (209 loc) · 10.1 KB
/
procstat.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/bin/bash
#########################################################################################################################
#
# SO - Trabalho 1
# Estatística de Processos em bash
#
# Este script permite a visualização da quantidade de memória total e da memória residente em memória física, do número
# total de bytes I/O,e da e taxa de leitura/escrita (bytes/sec) dos processos seleccionados nos últimos sec segundos.
#
# Pedro Sobral, nMec: 98491
# Daniel Figueireo, nMec: 98498
#
#########################################################################################################################
#Arrays
declare -A arrayAss=() # Array Associativo: está guardado a informação de cada processo, sendo a 'key' o PID
declare -A argOpt=() # Array Associativo: está guardada a informação das opções passadas como argumentos na chamada da função
declare -A R1=()
declare -A W1=()
i=0 #iniciação da variável i, usada na condição de verificação de opçoes de ordenac
re='^[0-9]+([.][0-9]+)?$'
#Função para quando argumentos passados são inválidos
function opcoes() {
echo "************************************************************************************************"
echo "OPÇÃO INVÁLIDA!"
echo " -c : Seleção de processos a utilizar através de uma expressão regular"
echo " -u : Seleção de processos a visualizar através do nome do utilizador"
echo " -r : Ordenação reversa"
echo " -s : Seleção de processos a visualizar num periodo temporal - data mínima"
echo " -e : Seleção de processos a visualizar num periodo temporal - data máxima"
echo " -d : Ordenação da tabela por RATER (decrescente)"
echo " -m : Ordenação da tabela por MEM (decrescente)"
echo " -t : Ordenação da tabela por RSS (decrescente)"
echo " -w : Ordenação da tabela pOR RATEW (decrescente)"
echo " -p : Número de processos a visualizar"
echo " Nota : As opções -d,-m,-t,-w não podem ser utilizadas em simultâneo"
echo "Último argumento: O último argumento passado tem de ser um número"
echo "************************************************************************************************"
}
#Tratamentos das opçoes passadas como argumentos
while getopts "c:u:rs:e:dmtwp:" option; do
#Adicionar ao array argOpt as opcoes passadas ao correr o procstat.sh, caso existam adiciona as que são passadas, caso não, adiciona "nada"
if [[ -z "$OPTARG" ]]; then
argOpt[$option]="nada"
else
argOpt[$option]=${OPTARG}
fi
case $option in
c) #Seleção de processos a utilizar atraves de uma expressão regular
str=${argOpt['c']}
if [[ $str == 'nada' || ${str:0:1} == "-" || $str =~ $re ]]; then
echo "Argumento de '-c' não foi preenchido, foi introduzido argumento inválido ou chamou sem '-' atrás da opção passada." >&2
opcoes
exit 1
fi
;;
s) #Seleção de processos a visualizar num periodo temporal - data mínima
str=${argOpt['s']}
regData='^((Jan(uary)?|Feb(ruary)?|Mar(ch)?|Apr(il)?|May|Jun(e)?|Jul(y)?|Aug(ust)?|Sep(tember)?|Oct(ober)?|Nov(ember)?|Dec(ember)?)) +[0-9]{1,2} +[0-9]{1,2}:[0-9]{1,2}'
if [[ $str == 'nada' || ${str:0:1} == "-" || $str =~ $re || ! "$str" =~ $regData ]]; then
echo "Argumento de '-s' não foi preenchido, foi introduzido argumento inválido ou chamou sem '-' atrás da opção passada." >&2
opcoes
exit 1
fi
;;
e) #Seleção de processos a visualizar num periodo temporal - data máxima
str=${argOpt['e']}
regData='^((Jan(uary)?|Feb(ruary)?|Mar(ch)?|Apr(il)?|May|Jun(e)?|Jul(y)?|Aug(ust)?|Sep(tember)?|Oct(ober)?|Nov(ember)?|Dec(ember)?)) +[0-9]{1,2} +[0-9]{1,2}:[0-9]{1,2}'
if [[ $str == 'nada' || ${str:0:1} == "-" || $str =~ $re || ! "$str" =~ $regData ]]; then
echo "Argumento de '-e' não foi preenchido, foi introduzido argumento inválido ou chamou sem '-' atrás da opção passada." >&2
opcoes
exit 1
fi
;;
u) #Seleção de processos a visualizar através do nome do utilizador
str=${argOpt['u']}
if [[ $str == 'nada' || ${str:0:1} == "-" || $str =~ $re ]]; then
echo "Argumento de '-u' não foi preenchido, foi introduzido argumento inválido ou chamou sem '-' atrás da opção passada." >&2
opcoes
opcoes exit 1
fi
;;
p) #Número de processos a visualizar
if ! [[ ${argOpt['p']} =~ $re ]]; then
echo "Argumento de '-p' tem de ser um número ou chamou sem '-' atrás da opção passada." >&2
opcoes
exit 1
fi
;;
r) #Ordenação reversa
;;
m | t | d | w)
if [[ $i = 1 ]]; then
#Quando há mais que 1 argumento de ordenacao
opcoes
exit 1
else
#Se algum argumento for de ordenacao i=1
i=1
fi
;;
*) #Passagem de argumentos inválidos
opcoes
exit 1
;;
esac
done
if [[ $# == 0 ]]; then
echo "Tem de passar no mínimo um argumento (segundos)."
opcoes
exit 1
fi
# Verificação se o último argumento passado é um numero
if ! [[ ${@: -1} =~ $re ]]; then
echo "Último argumento tem de ser um número."
opcoes
exit 1
fi
#Tratamento dos dados lidos
function listarProcessos() {
#Cabeçalho
printf "%-27s %-16s %15s %12s %12s %12s %12s %15s %15s %16s\n" "COMM" "USER" "PID" "MEM" "RSS" "READB" "WRITEB" "RATER" "RATEW" "DATE"
for entry in /proc/[[:digit:]]*; do
if [[ -r $entry/status && -r $entry/io ]]; then
PID=$(cat $entry/status | grep -w Pid | tr -dc '0-9') # ir buscar o PID
rchar1=$(cat $entry/io | grep rchar | tr -dc '0-9') # rchar inicial
wchar1=$(cat $entry/io | grep wchar | tr -dc '0-9') # wchar inicial
if [[ $rchar1 == 0 && $wchar == 0 ]]; then
continue
else
R1[$PID]=$(printf "%12d\n" "$rchar1")
W1[$PID]=$(printf "%12d\n" "$wchar1")
fi
fi
done
sleep $1 # tempo em espera
for entry in /proc/[[:digit:]]*; do
if [[ -r $entry/status && -r $entry/io ]]; then
PID=$(cat $entry/status | grep -w Pid | tr -dc '0-9') # ir buscar o PID
user=$(ps -o user= -p $PID) # ir buscar o user do PID
VmSize=$(cat $entry/status | grep VmSize | tr -dc '0-9') # ir buscar o VmSize
VmRss=$(cat $entry/status | grep VmRSS | tr -dc '0-9') # ir buscar o VmRss
comm=$(cat $entry/comm | tr " " "_") # ir buscar o comm,e retirar os espaços e substituir por '_' nos comm's com 2 nomes
if [[ -v argOpt[u] && ! ${argOpt['u']} == $user ]]; then
continue
fi
#Seleção de processos a utilizar atraves de uma expressão regular
if [[ -v argOpt[c] && ! $comm =~ ${argOpt['c']} ]]; then
continue
fi
LANG=en_us_8859_1
startDate=$(ps -o lstart= -p $PID) # data de início do processo atraves do PID
startDate=$(date +"%b %d %H:%M" -d "$startDate")
dateSeg=$(date -d "$startDate" +"%b %d %H:%M"+%s | awk -F '[+]' '{print $2}') # data do processo em segundos
if [[ -v argOpt[s] ]]; then #Para a opção -s
start=$(date -d "${argOpt['s']}" +"%b %d %H:%M"+%s | awk -F '[+]' '{print $2}') # data mínima
if [[ "$dateSeg" -lt "$start" ]]; then
continue
fi
fi
if [[ -v argOpt[e] ]]; then #Para a opção -e
end=$(date -d "${argOpt['e']}" +"%b %d %H:%M"+%s | awk -F '[+]' '{print $2}') # data máxima
if [[ "$dateSeg" -gt "$end" ]]; then
continue
fi
fi
rchar2=$(cat $entry/io | grep rchar | tr -dc '0-9') # rchar apos s segundos
wchar2=$(cat $entry/io | grep wchar | tr -dc '0-9') # wchar apos s segundos
subr=$rchar2-${R1[$PID]}
subw=$wchar2-${W1[$PID]}
rateR=$(echo "scale=2; $subr/$1" | bc -l) # calculo do rateR
rateW=$(echo "scale=2; $subw/$1" | bc -l) # calculo do rateW
arrayAss[$PID]=$(printf "%-27s %-16s %15d %12d %12d %12d %12d %15s %15s %16s\n" "$comm" "$user" "$PID" "$VmSize" "$VmRss" "${R1[$PID]}" "${W1[$PID]}" "$rateR" "$rateW" "$startDate")
fi
done
prints
}
function prints() {
if ! [[ -v argOpt[r] ]]; then
ordem="-rn"
else
ordem="-n"
fi
#Se não dermos nenhum valor ao -p, fica com o valor do tamanho do array
#Ou seja printa todos
if ! [[ -v argOpt[p] ]]; then
p=${#arrayAss[@]}
#Nº de processos que queremos ver
else
p=${argOpt['p']}
fi
if [[ -v argOpt[m] ]]; then
#Ordenação da tabela pelo MEM
printf '%s \n' "${arrayAss[@]}" | sort $ordem -k4 | head -n $p
elif [[ -v argOpt[t] ]]; then
#Ordenação da tabela pelo RSS
printf '%s \n' "${arrayAss[@]}" | sort $ordem -k5 | head -n $p
elif [[ -v argOpt[d] ]]; then
#Ordenação da tabela pelo RATER
printf '%s \n' "${arrayAss[@]}" | sort $ordem -k8 | head -n $p
elif [[ -v argOpt[w] ]]; then
#Ordenação da tabela pelo RATEW
printf '%s \n' "${arrayAss[@]}" | sort $ordem -k9 | head -n $p
else
#Ordenação default da tabela, ordem alfabética dos processos
ordem="-n" #Como é por ordem alfabética temos de mudar a ordem para '-n'
printf '%s \n' "${arrayAss[@]}" | sort $ordem -k1 | head -n $p
fi
}
listarProcessos ${@: -1} #este agumento passado, é para os segundos, visto que é passado em todas as opções, e é sempre o último