列出用户使用的所有 shell 类型

列出用户使用的所有 shell 类型

我正在寻找一种列出所有会话的方法,类似于命令 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 的实际名称(例如)。/^//.*/\Kbash/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需要的,这样才有完全匹配的进程(所以不需要fooshsh

现在我们有了目标 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

相关内容