Dans l'article précédent (https://qiita.com/minnsou/items/60a306510f613a666fec), après sudo rm -rf / *
, implémentez selective sorting pour obtenir la chaîne numérique saisie par l'utilisateur. J'ai fait quelque chose comme trier et écrire dans un fichier.
Je ne pouvais pas utiliser la commande ps
, donc j'ai à peine abordé les questions liées au processus. Donc, cette fois, je voudrais implémenter la commande ps
disparue uniquement à partir de la commande intégrée __bash __. Correctement cette fois aussi sudo rm -rf / *
depuis le début.
Fondamentalement, je présenterai les commandes et la syntaxe qui apparaissent, mais je ne traiterai pas de celles présentées dans l'article précédent telles que les définitions de fonctions et de variables, les tableaux, les instructions if et les instructions for en détail. Veuillez vous référer à Article précédent. Allons-y.
· Les références O'Reilly Japan Introduction bash
・ Environnement d'exécution Raspberry Pi 4 Model B+ Raspbian Buster Lite 2020-02-13-raspbian-buster-lite.img
Il y a beaucoup de commandes qui ont disparu avec sudo rm -rf / *
, mais ls
et cat
sont souvent utilisés et devraient être redéfinis. De plus, le complément est étrange, alors je vais le réparer.
Vous pouvez utiliser ʻecho * comme alias pour
ls(c'est-à-dire ʻalias ls = "echo *"
), mais comme c'est un gros problème, la commande ls
qui affiche le répertoire en bleu et les autres en blanc faire.
Pour ce faire, utilisez la commande test
(idem pour la commande [
). Cette commande utilise l'opérateur d'attribut __file __ pour déterminer la condition. Par exemple, l'opérateur d'attribut de fichier «-a» indique «si le fichier existe». Regardons un exemple concret.
Dans /
, le répertoire proc
existe et renvoie 0 comme statut de sortie, mais le répertoire bin
n'existe plus et renvoie 1.
Utilisez ceci pour créer la commande ls
. -d
est un opérateur d'attribut de fichier qui indique si un répertoire existe.
.bash
function ls
{
for i in *
do
if [ -d $i ]
then
echo -ne "\e[34m$i\e[m\t" #Le répertoire est bleu
else
echo -ne "$i\t" #A part ça, c'est blanc
fi
done
echo #Écho pour les sauts de ligne
}
J'ai renvoyé à l'article ici pour colorier avec ʻecho. De plus, le caractère de tabulation (
\ t) est inséré entre les noms de fichier. Utilisons réellement ce
lsdans un répertoire approprié. <img width="718" alt="スクリーンショット 2020-03-23 20.56.34.png " src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/2bf63ea8-0be9-56a1-ce0a-a9fc99e7cafb.png "> Les sauts de ligne sont un peu étranges contrairement au
lsnormal, mais faisons-le cette fois. Je pense que vous pouvez obtenir un résultat un peu plus beau si vous utilisez la variable shell
COLUMNS` qui représente le nombre de colonnes d'affichage du terminal pour séparer les cas.
Utilisez l'instruction while pour cela. La syntaxe est:
while <Expression conditionnelle>
do
<Une série de phrases>
done
Pour «
.bash
a=0
while [ $a -ne 3 ]
do
echo $a
let a++
done
«-ne» signifie pas égal. Lorsque la variable shell ʻaest différente de 3,
[$ a -ne 3] retourne un état de terminaison de 0 et boucle, et quand ʻa
devient 3, il retourne 1 et quitte la boucle. La commande intégrée let
évalue un opérateur arithmétique et affecte le résultat à une variable. Dans l'exemple ci-dessus, nous incrémentons simplement «a».
Lorsque vous l'essayez, ce sera comme suit. Lorsque ʻa` devient 3, vous pouvez voir que la commande s'est terminée correctement en quittant la boucle.
Maintenant, implémentons la commande cat
en utilisant l'instruction while. Pour plus de simplicité, nous n'implémenterons que la possibilité de prendre un argument et d'afficher son contenu.
.bash
function cat
{
while read val
do
echo $val
done
} < $1
La commande read
est une commande qui affecte une valeur à une variable shell. Dans cet exemple, la variable shell «val» reçoit le contenu du fichier ligne par ligne et s'affiche avec «écho». Lorsque le contenu du fichier spécifié par $ 1
est vide, la commande read
renvoie 1 comme état de fin, afin que vous puissiez sortir correctement de la boucle.
De plus, sudo rm -rf / *
peut ne pas être en mesure de bien se terminer avec tab.
↓ entrée de l'onglet
J'obtiens une erreur que je n'ai jamais vue. Vous pouvez voir ce qu'est l'achèvement de l'onglet dans la commande cat
en utilisant la commande intégrée complete
.
Cela signifie que l'achèvement de la commande cat
est déterminé par la fonction _longopt
. Vous pouvez voir les détails de cette fonction dans declare -f _longopt
, mais je ne vais pas y entrer ici. Le fait est que cette fonction __ ne fonctionne pas correctement à cause de l'effet de sudo rm -rf / *
.
Cette fois, faisons simplement __complement par le nom de fichier __. Plus précisément, écrivez comme suit en utilisant l'option -f
qui se termine à partir d'un nom de fichier normal.
complete -f cat
Comme mentionné dans Article précédent, la complétion du nom de fichier peut être faite avec ʻESC + / , mais maintenant cela peut aussi être fait avec tab. Au fait, rendons tab également disponible pour la commande
cd. Avec l'option
-d`, la complétion se fait à partir de __directory name __.
complete -d cd
Créons maintenant la commande ps
. Commencez par une description du répertoire / proc
qui contient les informations de processus.
Sous Linux, il existe un répertoire / proc
qui contient des informations sur les processus. Ceci est un pseudo répertoire différent du répertoire normal, et il ne disparaît pas même si sudo rm -rf / *
.
Quand vous le regardez, cela ressemble à ceci. Le répertoire composé uniquement des chiffres supérieurs contient les informations de processus correspondant à l'ID de processus (PID).
Au fait, ce répertoire / proc
existe sous Linux, mais sous UNIX pur (par exemple, FreeBSD et Mac OS BSD, Solaris basé sur System V, etc.) __ n'existe pas __, ou même s'il existe __ Veuillez noter que le contenu peut être différent __.
Jetons maintenant un coup d'œil au répertoire de l'ID de processus de ce shell de connexion (c'est-à-dire bash). Vous pouvez trouver l'ID de processus du shell actuel avec ʻecho $$ `. Il contient un fichier appelé «stat», qui contient des informations sur le processus. Commençons depuis le début.
(bash)
.R
signifie Running.Je ne peux pas tous les couvrir, alors voyez man proc
pour plus de détails.
La commande ps
capture ces valeurs et les affiche à l'écran. Cependant, la commande ps
par défaut est trop peu de processus à afficher, donc je voudrais créer une commande ps a
avec l'option ʻa, c'est-à-dire une commande
ps` qui affiche tous les processus qui ont des terminaux.
Tout d'abord, créez une fonction read_stat
qui prend ce fichier stat
comme argument et l'assigne à une variable shell.
.bash
function read_stat
{
read -a values
pid=${values[0]}
comm=${values[1]}
state=${values[2]}
tty_nr=${values[6]}
time=$(( ${values[13]} / 100 ))
} < $1
Tout d'abord, utilisez l'option -a
de la commande read
pour placer chaque valeur de stat
dans le tableau appelé values
. Vous trouverez ci-dessous une description des variables shell.
pid
--comm
Nom du fichier au format d'exécution
--state
État du processus
--tty_nr
Le nom du terminal auquel le processus est connecté
--time
Temps d'exécution (l'unité est en secondes)Je vais vraiment l'exécuter. Vous pouvez voir que la valeur est entrée correctement.
Je peux afficher les informations de base avec cela, mais le nom du terminal ne peut pas être affiché correctement. C'est parce que vous devez convertir le nombre de tty_nr
(34816 dans l'exemple ci-dessus) en une chaîne comme tty1
ou pts / 0
. Parlons un peu des fichiers device ici.
Dans les systèmes d'exploitation UNIX, le matériel tel que le disque dur, la mémoire USB et le terminal peuvent également être traités comme des fichiers. Un tel fichier est appelé device file. / Dev / null
pour ignorer la sortie et / dev / random
pour générer une chaîne aléatoire sont également des fichiers de périphérique que vous avez peut-être utilisés. Il existe deux types de fichiers de périphérique: block type et character type. Le premier est un fichier pour faire fonctionner les périphériques __disk, et le second est un fichier pour gérer d'autres choses.
Les fichiers de périphérique sont gérés à l'aide du __major number __ et du __minor number __. Vérifions la documentation Linux actuelle.
https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/devices.txt
Par exemple, "Numéro majeur 1 du fichier de périphérique bloc" est affecté au "disque RAM". Le nombre mineur indique le numéro du disque RAM.
Le terminal affiché par la commande ps
est essentiellement TTY device avec le numéro majeur 4 ou Unix98 PTY slave avec le numéro majeur 136. Le périphérique TTY est l'écran qui est directement connecté à Raspai, et l'esclave Unix98 PTY est un type de pseudo terminal, qui est l'écran lorsqu'il est connecté par __SSH.
Revenons maintenant à tty_nr
. La signification de cette chaîne numérique est écrite dans man proc
, je vais donc la citer.
(7) tty_nr %d The controlling terminal of the process. (The minor device number is contained in the combination of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.)
Les 31e à 20e et 7e à 0e bits de la chaîne numérique tty_nr
sont des nombres mineurs, et les 15e à 8e bits sont des nombres majeurs.
Utilisez-les pour créer une fonction qui affiche le nom du terminal dans la variable shell tty
.
.bash
function get_tty
{
major_num=$((tty_nr>>8))
minor_num=$((tty_nr&255))
if [ $major_num -eq 4 ]
then
tty=tty${minor_num}
elif [ $major_num -eq 136 ]
then
tty=pts/${minor_num}
else
tty=???
fi
}
Le nombre majeur est extrait en utilisant le décalage gauche de 8 bits (tty_nr >> 8
), et le nombre mineur est extrait du produit logique ( tty_nr & 255
) avec 255 qui est 11111111 en binaire. En fait, ce n'est pas précis à moins d'utiliser 31 à 20 bits, mais cette fois, il n'y a pas de problème, donc je l'ai fait de cette façon.
Si le nombre majeur est 4, c'est un terminal normal (tty1
, etc.), s'il est 136, c'est un pseudo-terminal ( pts / 0
, etc.), sinon il est inconnu (???
), et celui qui lui correspond est la variable shell tty. Attribué à
.
Utilisons-le réellement. Puisque cette expérience a été réalisée en se connectant depuis mac avec SSH, le pseudo terminal s'est affiché correctement.
Créez une commande ps
en utilisant les fonctions read_stat
et get_tty
créées jusqu'à présent.
.bash
function ps {
echo -e "PID\tTTY\tSTATE\tTIME\tCMD"
for stat in /proc/[1-9]*/stat #Considérez un répertoire qui commence par un nombre et a une statistique
do
read_stat $stat
if [ $tty_nr -ne 0 ] #Afficher uniquement les processus avec des terminaux
then
get_tty #Obtenez tty
echo -e "${pid}\t${tty}\t${state}\t${time}\t${comm:1:-1}" #De la valeur de la communication()Retirer
fi
done
}
Ici, la variable shell comm
a une chaîne entre parenthèses, donc je l'ai supprimée et l'ai sortie ($ {comm: 1: -1}
).
Utilisons-le réellement. Il a été produit correctement. Cette fois, j'ai également constaté que bash s'exécute sur le moniteur qui est directement connecté à la tarte aux râpes et que son PID est 614.
Je pense que vous pouvez réaliser que vous pouvez faire n'importe quoi de manière inattendue avec uniquement les commandes intégrées de bash. Si j'ai le temps, j'aimerais parler de la gestion des processus (concepts de travail, commandes kill
, signaux, etc.).