我正在寻找一种列出所有会话的方法,类似于命令 who,它还会列出用户列表正在使用的 shell 类型。
答案1
根据你的需要,你可以使用who
的堂兄w
:
$ w
17:40:49 up 11 days, 22:38, 4 users, load average: 0.14, 0.13, 0.10
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
muru tty7 :0 12Jan17 11days 2:24m 0.37s /sbin/upstart --user
muru pts/24 127.0.0.1:S.0 17:36 0.00s 0.41s 0.00s w
muru pts/26 127.0.0.1:S.2 17:38 2:33 0.19s 0.19s -/bin/zsh
它在登录终端上运行 active 命令。你可以使用终端 ID 查看我最初启动了哪个 shell:
$ w -h | awk '{print $2}' | xargs -L1 pgrep -oat
1969 /usr/lib/xorg/Xorg -core :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
12703 -/bin/zsh
13398 -/bin/zsh
pgrep
能:
- 使用终端匹配(
-t
) - 打印最早匹配的进程(
-o
) - 打印整个命令行(
-a
)
答案2
这是一个脚本,列出了 shell 的 PID、它的二进制文件、shell 的 stdin 所附加的终端以及进程所有者的用户名。该脚本大量使用/proc
文件系统以提高准确性。
下面的屏幕截图中显示的是该脚本的示例运行。我使用 Terminator 终端仿真器打开了两个分割。每个提示符方括号中的数字是该 shell 的 PID。顶部分割确认我mksh
在虚拟伪终端(即 GUI 终端)中打开了两个实例,以及一个 bash 实例。mksh
可以在 中找到另一个实例tty1
。同样有趣的是,有两个dash
实例附加到/dev/null
。检查它们所属的进程后,发现它们属于一个 Unity appindicator 和 zeitgeist 服务。因此,在此脚本中,可以更容易地看到哪些 shell 实际上是由真实用户使用的,哪些是由系统进程使用的。
脚本源代码如下,也可在GitHub
#!/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
答案3
由于系统中已安装的所有 shell 都列在 中/etc/shells
,因此您可以从那里开始并使用ps
列出正在运行的 shell 以及相关信息。
因此,首先获取 shell 列表:
$ grep -oP '^/.*/\K.*' /etc/shells | sort -u
bash
csh
dash
fish
ksh
mksh
sh
tcsh
zsh
表示-o
“仅打印行的匹配部分”,-P
启用 PCRE(Perl 兼容正则表达式),这让我们可以使用诸如 之类的花哨东西\K
,这意味着“忽略到目前为止匹配的所有内容”。因此,表示匹配以( )^/.*/\K.*
开头的行,然后匹配尽可能多的字符直到( ),然后忘记到目前为止匹配的内容 ( ) 并匹配其他所有内容直到行尾。这将有效地返回每行的最后一部分,即 shell 的实际名称(例如)。/
^/
/
.*/
\K
bash
/bin/bash
just确保不会有 shell 被打印两次(有时在和sort -u
中可能会有相同的 shell )。/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
该perl
命令只是用 替换换行符 ( \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
)sh
。
现在我们有了目标 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、使用的命令、启动它的用户以及它所连接的终端设备。
答案4
带有子进程的 Shell 信息
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