Я ищу способ перечислить все сеансы, что-то вроде команды who, которая также указала бы тип оболочки, используемой списком пользователей.
Поскольку все установленные оболочки в вашей системе указаны в /etc/shells, вы можете начать оттуда и использовать ps, чтобы указать, какие из них выполняются, и соответствующую информацию.
Итак, сначала получим список оболочек:
$ grep -oP '^/.*/\K.*' /etc/shells | sort -u
bash
csh
dash
fish
ksh
mksh
sh
tcsh
zsh
-o означает «распечатать только соответствующую часть строки», а -P включает PCRE, Perl Compatible Regular Expressions, которые позволяют использовать такие необычные вещи, как \K, что означает «игнорировать все, что соответствует этому моменту». Таким образом, ^/.*/\K.* означает строки соответствия, начинающиеся с / (^/), а затем как можно больше символов до / (.*/), затем забудьте о том, что было сопоставлено до сих пор (\K). и сопоставлять все остальное до конца строки. Это будет эффективно возвращать последнюю часть каждой строки, фактическое имя оболочки (например, bash для /bin/bash).
sort -u просто гарантирует, что никакие оболочки не печатаются дважды (иногда вы можете имеют ту же оболочку как в /bin, так и /usr/bin).
Но мы хотим использовать этот список для поиска вывода ps, поэтому нам нужно его в формате, который grep может понять:
$ grep -oP '^/.*/\K.*' /etc/shells | sort -u | perl -pe '!eof && s/\n/\|/'
bash|csh|dash|fish|ksh|mksh|sh|tcsh|zsh
Что [ f23] просто заменяет символы новой строки (\n) на |, поэтому ее можно напрямую подать на grep.
Теперь мы используем pgrep для перечисления всех процессов сопоставления:
$ pgrep -x "$(grep -oP '^/.*/\K.*' /etc/shells | sort -u |
perl -pe '!eof && s/\n/\|/')"
1235
5399
14031
14116
14200
14304
14337
14392
15257
15368
15551
15601
15704
15877
17033
28177
29138
30797
32404
32656
Требуется -x, чтобы только те процессы, которые точно соответствуют (поэтому нет foosh для [ f30]).
Теперь, когда у нас есть список целевых PID, мы можем передать их в ps и использовать его для печати соответствующей информации:
$ pgrep -x "$(grep -oP '^/.*/\K.*' /etc/shells | sort -u |
perl -pe '!eof && s/\n/\|/')" |
while read pid; do ps -p $pid -o pid=,cmd=,euser=,tty=; done
1235 /bin/bash terdon pts/1
5399 /bin/bash terdon pts/4
12341 /bin/bash terdon pts/2
14031 /bin/bash terdon pts/8
14116 /bin/bash terdon pts/9
14200 /bin/bash terdon pts/10
14304 /bin/bash terdon pts/11
14337 /bin/bash terdon pts/12
14392 /bin/bash terdon pts/13
15257 dash terdon pts/13
15368 zsh terdon pts/12
15551 mksh terdon pts/11
15601 -sh terdon pts/10
15704 -csh terdon pts/9
15877 sh terdon pts/8
17033 /bin/bash terdon pts/2
28177 /bin/bash terdon pts/3
29138 fish terdon pts/3
30797 /bin/bash terdon pts/5
32404 /bin/bash terdon pts/6
32656 /bin/bash terdon pts/7
Это читает каждый PID, созданный предыдущими шагами, и запускает ps для него (-p $pid), используя флаг -o для управления выводом для печати ПИД-кода, используемой командой, пользователя, который запустил его и подключенного к нему терминала к.
Вот сценарий, в котором перечислены PID оболочки, ее двоичный код, терминал, к которому прикреплен stdin оболочки, и имя пользователя владельца процесса. Скрипт широко использует файловую систему /proc для лучшей точности.
Что вы видите на скриншоте ниже, это образец запуска этого скрипта. У меня есть два раскола, открытых с эмулятором терминала Terminator. Число в квадратных скобках каждого приглашения - это PID этой оболочки. Верхний раскол подтверждает, что у меня есть два экземпляра mksh, открытых в виртуальных псевдотерминалах, которые являются терминалами GUI, и один экземпляр bash. Другой экземпляр mksh можно найти в tty1. Интересно также, что есть два экземпляра dash, прикрепленных к /dev/null. Изучая процессы, к которым они принадлежат, выясняется, что они принадлежат одному обсерватору Unity и услуге zeitgeist. Таким образом, в этом скрипте легче увидеть, какие оболочки действительно используются реальными пользователями, а какие - системными процессами.
Источник сценария ниже, а также доступен
#!/usr/bin/env bash
is_self(){
if [ "$link" == "/bin/bash" ] && grep -q $0 /proc/$proc_pid/cmdline
then
return 0
else
return 1
fi
}
print_proc_info(){
terminal=$( readlink -e "/proc/$proc_pid/fd/0" )
[ -z "$terminal" ] && terminal=$'\t'
printf "%s\t%s\t%s\t" "$proc_pid" "$1" "$terminal"
stat --printf="%U\n" /proc/"$proc_pid"/mountstats
}
find_process(){
local function_pid=$$
local search_base=$(basename "$1")
find /proc -maxdepth 1 -type d -path "*/[1-9]*" | while read -r proc_dir;
do
local proc_pid=$(basename "$proc_dir")
local link=$(readlink -e "$proc_dir"/exe)
local name=$( awk 'NR==1{print $2}' "$proc_dir"/status 2>/dev/null )
if is_self ; then continue ; fi
if [ "$link" == "$1" ] ||
[ -z "$link" ] && [ "$name" = "$search_base" ]
then
print_proc_info $1
# make additional check if readlink wasn't allowed to
# get where /proc/[pid]/exe is symlinked
fi
done
}
main(){
while read -r shell
do
find_process "$shell"
done < /etc/shells
echo "Done, press [ENTER] to continue"
read
}
main
Информация о оболочке с дочерними процессами
ps -efH | egrep 'pts/|tty'
sup 14536 2065 0 17:05 pts/19 00:00:00 bash
sup 14572 14536 0 17:05 pts/19 00:00:00 dash
sup 14575 14572 0 17:05 pts/19 00:00:00 bash
sup 14611 14575 0 17:05 pts/19 00:00:00 dash
sup 14673 1956 0 17:06 pts/6 00:00:00 /bin/bash
sup 14717 14673 0 17:06 pts/6 00:00:00 bash
sup 15650 14717 0 17:16 pts/6 00:00:00 ps -efH