web-dev-qa-db-fra.com

Liste de tous les types de shell utilisés par les utilisateurs

Je cherche un moyen de répertorier toutes les sessions, quelque chose comme la commande who, qui indiquerait également le type de shell utilisé par la liste des utilisateurs.

6
Dave Bourbeau

Selon ce que vous voulez, vous pouvez utiliser le cousin de who de 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

Il exécute la commande active sur le terminal de connexion. Vous pouvez utiliser l'ID de terminal pour voir quel shell j'ai démarré à l'origine:

$ 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 peut:

  • correspondre à l'aide d'un terminal (-t)
  • imprimer le processus de correspondance le plus ancien (-o)
  • affiche la ligne de commande complète (-a)
3
muru

Comme tous les shells installés sur votre système sont répertoriés dans /etc/shells, vous pouvez commencer à partir de là et utiliser ps pour répertorier ceux qui sont en cours d'exécution et les informations associées.

Alors, d'abord, obtenez la liste des coquillages:

$ grep -oP '^/.*/\K.*' /etc/shells | sort -u
bash
csh
dash
fish
ksh
mksh
sh
tcsh
zsh

-o signifie "n'imprime que la partie correspondante de la ligne" et -P active PCRE, expressions régulières compatibles Perl, qui nous permettent d'utiliser des éléments fantaisistes tels que \K, qui signifie "tout ignorer assorties à ce point ". Donc, ^/.*/\K.* signifie faire correspondre les lignes commençant par un / (^/), puis autant de caractères que possible jusqu'à un / (.*/), puis oublier ce qui était assorti jusqu'à présent (\K) et correspond à tout le reste jusqu'à la fin de la ligne. Cela renverra effectivement la dernière partie de chaque ligne, le nom réel du shell (par exemple, bash pour /bin/bash).

Le sort -u s'assure simplement qu'aucun shell n'est imprimé deux fois (vous pouvez parfois avoir le même Shell dans les deux /bin et /usr/bin).

Mais nous souhaitons utiliser cette liste pour rechercher la sortie de ps, nous en avons donc besoin dans un format que grep peut comprendre:

$ grep -oP '^/.*/\K.*' /etc/shells | sort -u | Perl -pe '!eof && s/\n/\|/'
bash|csh|dash|fish|ksh|mksh|sh|tcsh|zsh

Cette commande Perl remplace simplement les caractères de nouvelle ligne (\n) par |, afin que cela puisse être directement transmis à grep.

Nous utilisons maintenant pgrep pour répertorier tous les processus correspondants:

$ 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

Le -x est nécessaire pour que seuls les processus qui correspondent exactement (donc pas de foosh pour sh).

Maintenant que nous avons la liste des PID cibles, nous pouvons les transmettre à ps et les utiliser pour imprimer les informations pertinentes:

$ 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

Ceci lit chaque PID produit par les étapes précédentes et exécute ps pour lui (-p $pid), en utilisant le drapeau -o pour contrôler la sortie pour imprimer le PID, la commande utilisée, l'utilisateur qui l'a lancé. lui et le terminal auquel il est attaché.

1
terdon

Informations shell avec processus enfants

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
1
Nir Vana

Voici un script qui répertorie le PID d'un shell, son binaire, le terminal auquel le stdin du shell est attaché et le nom d'utilisateur du propriétaire du processus. Le script utilise largement le système de fichiers /proc pour une meilleure précision.

Ce que vous voyez dans la capture d'écran ci-dessous est un exemple d'exécution de ce script. J'ai deux divisions ouvertes avec l'émulateur de terminal Terminator. Le nombre entre crochets de chaque invite correspond au PID de ce shell. La division du haut confirme que deux instances mksh sont ouvertes dans des pseudo-terminaux virtuels, à savoir des terminaux à interface graphique, et une instance bash. Une autre instance de mksh peut être trouvée dans tty1. Ce qui est également intéressant, c’est qu’il existe deux instances dash attachées à /dev/null. En examinant les processus auxquels ils appartiennent, il s’avère que ceux-ci appartiennent à un seul service Unity Indicator et Zeitgeist. Ainsi, dans ce script, il est plus facile de voir quels shells sont réellement utilisés par de vrais utilisateurs, et lesquels par les processus système.

enter image description here

La source du script est ci-dessous et également disponible sur 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 
1
Sergiy Kolodyazhnyy