Наличие "среднего числа загрузки на пользователя" не имеет большого смысла, так как среднее число загрузки только имеет смысл в контексте большей системы. Можно, однако, получить информацию использования, которая могла бы быть тем, что Вы хотите. sa
от psacct
может сделать это, например:
# sa
223730 62617.91re 31.57cp 0avio 5583k
284 1515.73re 10.45cp 0avio 46067k perl
314 17.53re 8.90cp 0avio 65746k redis-server*
152 1779.02re 6.46cp 0avio 56377k vim
8 2503.01re 1.69cp 0avio 6089k snort*
11209 99.64re 1.52cp 0avio 6100k git
20269 33.24re 0.48cp 0avio 30273k postgres*
140 0.48re 0.37cp 0avio 1831k sort
3 1193.10re 0.26cp 0avio 128389k pipe_errorlog.c
7 3146.93re 0.20cp 0avio 156983k apache2*
26 0.16re 0.15cp 0avio 32113k ack
19 2692.45re 0.12cp 0avio 14226k sshd
10 0.22re 0.11cp 0avio 14464k apt-show-versio
25 5.58re 0.08cp 0avio 7042k apt-get
118 0.40re 0.08cp 0avio 9674k find
4 1.51re 0.08cp 0avio 1212k rkhunter
377 0.33re 0.07cp 0avio 14768k rm
226 2696.40re 0.05cp 0avio 11524k bash
# sa -m
root 201825 17279.57re 13.26cp 0avio 2981k
110 255 14.86re 7.61cp 0avio 65544k
nobody 222 4659.53re 7.24cp 0avio 38149k
snort 1 1440.00re 1.60cp 0avio 25792k
108 763 798.83re 1.24cp 0avio 6964k
105 12801 31.79re 0.47cp 0avio 33102k
114 94 2741.65re 0.09cp 0avio 9906k
109 7 16944.24re 0.02cp 0avio 25483k
Debian-exim 3772 0.81re 0.00cp 0avio 25086k
man 182 0.02re 0.00cp 0avio 5203k
116 11 796.78re 0.00cp 0avio 9823k
107 10 795.09re 0.00cp 0avio 9823k
statd 3690 0.68re 0.00cp 0avio 25532k
sshd 22 0.44re 0.00cp 0avio 12690k
www-data 3 0.00re 0.00cp 0avio 11603k
111 2 17112.17re 0.00cp 0avio 19048k
mail 1 0.00re 0.00cp 0avio 11184k
Чистое решение на bash, никаких внешних инструментов, используемых для обработки строк, только расширение параметров:
#! /bin/bash
str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'
IFS=: read -a fields <<< "$str"
for (( i=0 ; i < ${#fields[@]} ; i++ )) ; do
f=${fields[i]}
notfirst=$(( i>0 ))
last=$(( i+1 == ${#fields[@]} ))
(( notfirst )) && echo -n ${f% *}
start=('' $'\n' ' ')
colon=('' ': ')
echo -n "${start[notfirst + last]}${f##* }${colon[!last]}"
done
echo
Объяснение: $ notfirst
и $ last
- логические. Часть перед последним пробелом $ {f% *}
не печатается для первого поля, так как такого нет. $ start
и $ двоеточие
содержат различные строки, разделяющие поля: в первом элементе notfirst + last
равно 0, поэтому ничего не добавляется в начале, для остальных из строк $ notfirst
равно 1, поэтому печатается новая строка, а для последней строки добавление дает 2, поэтому печатается пробел. Затем печатается часть после последнего пробела $ {f ## *}
. Двоеточие печатается для всех строк, кроме последней.
dd if=/dev/sda bs=512 count=63 | hexdump -C
Объяснение
\S+:[1124455] совпадает с концом строки на [1124456]:[1124457].
Вы можете использовать awk (1) со следующим скриптом split.awk:
BEGIN { RS=" "; first=1; }
first { first=0; printf "%s", $1; next; }
/[a-z]+\.[^:]+:/ { printf "\n%s", $1; next; }
{ printf " %s", $1 }
END { printf "\n" }
Когда вы запустите
awk -f split.awk input.dat
, вы получите
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Идея состоит в том, чтобы позволить awk разделить ввод, когда он видит пробел (установка записи разделитель RS в строке 1). Затем он сопоставляет xxx.yy.zz: значениям в строках 2 и 3 (отличая самое первое совпадение от последующих), а строка 4 соответствует, когда строки 2 и 3 не совпадают. Строка 5 просто выводит последнюю новую строку.
Проще использовать инструмент, поддерживающий поисковые запросы:
$ s="battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500"
$ grep -oP '\S+:\s+.*?(?=\s+\S+:|$)' <<< "$s"
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Если вам нужен результат в виде массива:
$ IFS=$'\n' foo=($(grep -oP '\S+:\s+.*?(?=\s+\S+:|$)' <<< "$s"))
$ for i in "${!foo[@]}"; do echo "$i<==>${foo[i]}"; done
0<==>battery.charge: 90
1<==>battery.charge.low: 30
2<==>battery.runtime: 3690
3<==>battery.voltage: 230.0
4<==>device.mfr: MGE UPS SYSTEMS
5<==>device.model: Pulsar Evolution 500
РЕДАКТИРОВАТЬ: Объяснение регулярного выражения:
'\S+:\s+.*?(?=\s+\S+:|$)'
\ S +
соответствует одному или нескольким непробельным символам :
соответствует :
\ s +
соответствует одному или нескольким пробелам после :
.*?
обозначает нежадное совпадение (? = \ S + \ S +: | $)
- это предварительное утверждение для определения наличия:
Таким образом, строка разбивается на части, например battery.charge: 90
, ... device.mfr: MGE UPS SYSTEMS
, ...
Ниже приведены ссылки на несколько онлайн-анализаторов регулярных выражений:
С GNU sed вы можете сопоставить каждую непрерывную строку (т. Е. Без пробелов), оканчивающуюся :
, а затем поместить новую строку перед всеми, кроме первой:
sed 's/[^[:space:]]\+:/\n&/g2'
Если ваша версия sed не поддерживает расширение gn
, вы можете использовать простой модификатор g
sed 's/[^[:space:]]\{1,\}:/\
&/g'
, который будет работать так же, за исключением печати дополнительной новой строки перед первой ключ. Вы можете использовать perl -pe 's / \ S +: / \ n $ & / g'
с той же оговоркой (может быть Perl-эквивалент GNU sed g2
, но я не знаю).
Вот наивный подход, который должен работать, если вам все равно, что табуляции и новые строки во вводе (если есть) преобразованы в простые пробелы.
Идея проста: разделить ввод на пробелы и распечатать каждый токен, за исключением того, что вы добавляете токены, заканчивающиеся на :
, с новой строкой (и повторно добавляете пробел перед другими). Переменная $ count
и связанная с ней if
полезны только для предотвращения начальной пустой строки. Можно удалить, если не проблема. (Сценарий предполагает, что ввод находится в файле с именем intput
в текущем каталоге.)
#! /bin/bash
count=0
for i in $(<input) ; do
fmt=
if [[ $i =~ :$ ]] ; then
if [[ $count -gt 0 ]] ; then
fmt="\n%s"
else
fmt="%s"
fi
((count++))
else
fmt=" %s"
fi
printf "$fmt" "$i"
done
echo
echo "Num items: $count"
Я надеюсь, что кто-то сможет придумать более хорошую альтернативу.
$ cat input
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
$ ./t.sh
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Num items: 6
Вот короткий awk
скрипт для демонстрации awk
мощности.
awk '
len=patsplit($0, namesArr,"[^ :]+: ", valuesArr) {
for(i=0;i<=len;i++)
print namesArr[i], valuesArr[i]
}' input.txt
input.txt
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
выход:
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500