Im vorherigen Artikel (https://qiita.com/minnsou/items/60a306510f613a666fec) implementieren Sie nach "sudo rm -rf / *" selective sorting, um die vom Benutzer eingegebene numerische Zeichenfolge abzurufen. Ich habe so etwas wie Sortieren und Schreiben in eine Datei gemacht.
Ich konnte den Befehl ps
nicht verwenden, daher habe ich prozessbezogene Angelegenheiten kaum angesprochen. Daher möchte ich dieses Mal den verschwundenen Befehl "ps" nur über den integrierten Befehl __bash __ implementieren. Richtig diesmal auch sudo rm -rf / *
von Anfang an.
Grundsätzlich werde ich die Befehle und die Syntax einführen, die angezeigt werden, aber ich werde mich nicht mit den im vorherigen Artikel eingeführten Befehlen wie Funktions- und Variablendefinitionen, Arrays, if-Anweisungen und detaillierten Anweisungen befassen. Weitere Informationen finden Sie unter Vorheriger Artikel. Lass uns gehen.
· Verweise O'Reilly Japan Einführung Bash
・ Ausführungsumgebung Raspberry Pi 4 Model B+ Raspbian Buster Lite 2020-02-13-raspbian-buster-lite.img
Es gibt viele Befehle, die mit "sudo rm -rf / *" verschwunden sind, aber "ls" und "cat" werden häufig verwendet und sollten neu definiert werden. Auch die Ergänzung ist seltsam, also werde ich es beheben.
Sie können echo *
als Alias für ls
verwenden (dh alias ls =" echo * "
), aber da es eine große Sache ist, der Befehl ls
, der das Verzeichnis in blau und die anderen in weiß anzeigt machen.
Verwenden Sie dazu den Befehl test
(dasselbe gilt für den Befehl [
). Dieser Befehl verwendet den __file-Attributoperator __, um die Bedingung zu bestimmen. Beispielsweise gibt der Dateiattributoperator "-a" an, ob die Datei vorhanden ist. Schauen wir uns ein konkretes Beispiel an.
In /
existiert das Verzeichnis proc
und gibt 0 als Exit-Status zurück, aber das Verzeichnis bin
existiert nicht mehr und gibt 1 zurück.
Verwenden Sie diese Option, um den Befehl ls
zu erstellen. -d ist ein Dateiattributoperator, der angibt, ob ein Verzeichnis vorhanden ist.
.bash
function ls
{
for i in *
do
if [ -d $i ]
then
echo -ne "\e[34m$i\e[m\t" #Das Verzeichnis ist blau
else
echo -ne "$i\t" #Davon abgesehen ist es weiß
fi
done
echo #Echo für Zeilenumbrüche
}
Ich habe auf den Artikel hier verwiesen, um ihn mit "echo" zu färben. Außerdem wird das Tabulatorzeichen (\ t
) zwischen die Dateinamen eingefügt. Verwenden wir dieses ls
tatsächlich in einem geeigneten Verzeichnis.
Die Zeilenumbrüche sind im Gegensatz zu den normalen "ls" etwas seltsam, aber machen wir es diesmal. Ich denke, dass Sie etwas schöner ausgeben können, wenn Sie die Shell-Variable "COLUMNS" verwenden, die die Anzahl der Anzeigespalten des Terminals darstellt, um die Fälle zu trennen.
Verwenden Sie dazu die while-Anweisung. Die Syntax lautet:
while <Bedingter Ausdruck>
do
<Eine Reihe von Sätzen>
done
Wie die if-Anweisung verwendet der
.bash
a=0
while [ $a -ne 3 ]
do
echo $a
let a++
done
-ne
bedeutet nicht gleich. Wenn die Shell-Variable "a" nicht 3 ist, gibt "[$ a -ne 3]" den Endstatus 0 und Schleifen zurück, und wenn "a" 3 wird, gibt sie 1 zurück und verlässt die Schleife. Der eingebaute Befehl let
wertet einen arithmetischen Operator aus und weist das Ergebnis einer Variablen zu. Im obigen Beispiel erhöhen wir einfach "a".
Wenn Sie es tatsächlich versuchen, wird es wie folgt sein.
Lassen Sie uns nun den Befehl cat
mit der while-Anweisung implementieren. Der Einfachheit halber werden wir nur die Fähigkeit implementieren, ein Argument zu nehmen und seinen Inhalt anzuzeigen.
.bash
function cat
{
while read val
do
echo $val
done
} < $1
Der Befehl "Lesen" ist ein Befehl, der einer Shell-Variablen einen Wert zuweist. In diesem Beispiel wird der Shell-Variablen "val" der Inhalt der Datei zeilenweise zugewiesen und mit "echo" angezeigt. Wenn der Inhalt der durch "$ 1" angegebenen Datei leer ist, gibt der Befehl "read" 1 als Endstatus zurück, damit Sie die Schleife ordnungsgemäß verlassen können.
Außerdem kann sudo rm -rf / *
möglicherweise nicht gut mit tab abgeschlossen werden.
↓ Tab-Eingabe
Ich erhalte einen Fehler, den ich noch nie gesehen habe. Sie können sehen, welche Tab-Vervollständigung im Befehl cat
enthalten ist, indem Sie den integrierten Befehl complete
verwenden.
Dies bedeutet, dass der Abschluss des Befehls "cat" durch die Funktion "_longopt" bestimmt wird. Sie können die Details dieser Funktion in declare -f _longopt
sehen, aber ich werde hier nicht darauf eingehen. Der Punkt ist, dass diese Funktion __ aufgrund des Effekts von sudo rm -rf / *
nicht richtig funktioniert.
Lassen Sie uns diesmal einfach __komplementieren nach Dateiname __ durchführen. Schreiben Sie insbesondere wie folgt mit der Option "-f", die aus einem normalen Dateinamen hervorgeht.
complete -f cat
Wie in Vorheriger Artikel erwähnt, kann die Vervollständigung des Dateinamens mit "ESC + /" erfolgen, jetzt jedoch auch mit der Registerkarte. Lassen Sie uns übrigens auch die Registerkarte für den Befehl cd
verfügbar machen. Mit der Option -d
erfolgt die Vervollständigung über __Verzeichnisname __.
complete -d cd
Lassen Sie uns nun den Befehl ps
erstellen. Beginnen Sie mit einer Beschreibung des Verzeichnisses / proc
, das Prozessinformationen enthält.
Unter Linux gibt es ein Verzeichnis / proc, das Prozessinformationen enthält. Dies ist ein Pseudoverzeichnis, das sich vom normalen Verzeichnis unterscheidet und auch dann nicht verschwindet, wenn sudo rm -rf / *
.
Wenn man es sich tatsächlich ansieht, sieht es so aus. Das Verzeichnis, das nur aus den oberen Nummern besteht, enthält die Prozessinformationen, die der Prozess-ID (PID) entsprechen.
Übrigens existiert dieses / proc
-Verzeichnis unter Linux, aber unter reinem UNIX (z. B. BSD-basiertes FreeBSD und Mac OS, System V-basiertes Solaris usw.) __ existiert nicht __ oder auch wenn es existiert __ Bitte beachten Sie, dass der Inhalt unterschiedlich sein kann __.
Schauen wir uns nun das Verzeichnis der Prozess-ID dieser Login-Shell an (dh Bash). Sie finden die Prozess-ID der aktuellen Shell mit "echo $$". Darin befindet sich eine Datei namens "stat", die Informationen über den Prozess enthält. Fangen wir von vorne an.
(bash)
.
――Das dritte ist "R" im Status des Prozesses. R
steht für Laufen.Ich kann nicht alle behandeln, also siehe "man proc" für Details.
Der Befehl ps
erfasst diese Werte und zeigt sie auf dem Bildschirm an. Die Standardeinstellung des Befehls "ps" ist jedoch, dass zu wenige Prozesse zum Anzeigen vorhanden sind. Daher möchte ich einen Befehl "ps a" mit der Option "a" erstellen, dh einen Befehl "ps", der alle Prozesse mit Terminals anzeigt.
Erstellen Sie zunächst eine Funktion "read_stat", die diese "stat" -Datei als Argument verwendet und einer Shell-Variablen zuweist.
.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
Verwenden Sie zuerst die Option "-a" des Befehls "read", um jeden Wert von "stat" in ein Array mit dem Namen "values" einzufügen. Unten finden Sie eine Beschreibung der Shell-Variablen.
--pid
Prozess-ID
--comm
Dateiname des Ausführungsformats
--state
Prozessstatus
--tty_nr
Der Name des Terminals, mit dem der Prozess verbunden ist
--time
Ausführungszeit (Einheit ist Sekunden)
Ich werde es tatsächlich ausführen. Sie können sehen, dass der Wert richtig eingegeben wurde.
Ich kann damit die grundlegenden Informationen anzeigen, aber der Terminalname kann nicht gut angezeigt werden. Das liegt daran, dass Sie die Zahl in tty_nr
(34816 im obigen Beispiel) in eine Zeichenfolge wie tty1
oder pts / 0
konvertieren müssen. Lassen Sie uns hier ein wenig über Gerätedateien sprechen.
Unter UNIX-basierten Betriebssystemen können Hardware wie Festplatte, USB-Speicher und Terminal auch als Dateien behandelt werden. Eine solche Datei heißt __ Gerätedatei__. / Dev / null
zum Verwerfen der Ausgabe und / dev / random
zum Generieren einer zufälligen Zeichenfolge sind ebenfalls Gerätedateien, die Sie möglicherweise verwendet haben. Es gibt zwei Arten von Gerätedateien: block type und character type. Ersteres ist eine Datei zum Bedienen von __disk-Geräten, und letzteres ist eine Datei zum Behandeln anderer Dinge.
Gerätedateien werden mit __major number __ und __minor number __ verwaltet. Lassen Sie uns die aktuelle Linux-Dokumentation überprüfen.
https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/devices.txt
Beispielsweise wird "Hauptnummer 1 der Blockgerätedatei" der "RAM-Platte" zugewiesen. Die Nebennummer gibt die Nummer der RAM-Disk an.
Das vom Befehl ps
angezeigte Terminal ist im Grunde TTY device mit der Hauptnummer 4 oder Unix98 PTY-Slave mit der Hauptnummer 136. Das TTY-Gerät ist der Bildschirm, der direkt mit Raspai verbunden ist, und der Unix98-PTY-Slave ist eine Art Pseudo-Terminal, bei dem es sich um den Bildschirm handelt, wenn er über __SSH verbunden ist.
Kehren wir nun zu tty_nr
zurück. Die Bedeutung dieser numerischen Zeichenfolge ist in "man proc" geschrieben, daher werde ich sie zitieren.
(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.)
Die 31. bis 20. und 7. bis 0. Bits der numerischen Zeichenfolge "tty_nr" sind Nebenzahlen, und die 15. bis 8. Bits sind Hauptzahlen.
Verwenden Sie diese, um eine Funktion zu erstellen, die den Terminalnamen in der Shell-Variablen tty
anzeigt.
.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
}
Die Hauptzahl wird unter Verwendung einer 8-Bit-Linksverschiebung (tty_nr >> 8
) extrahiert, und die Nebenzahl wird aus dem logischen Produkt ( tty_nr & 255
) mit 255 extrahiert, was 11111111 in Binärform ist. Eigentlich ist es nicht genau, es sei denn, Sie verwenden 31 bis 20 Bit, aber diesmal gibt es kein Problem, also habe ich es so gemacht.
Wenn die Hauptzahl 4 ist, ist es ein normales Terminal ("tty1" usw.), wenn es 136 ist, ist es ein Pseudo-Terminal ("pts / 0" usw.), andernfalls ist es unbekannt ("???"), und dasjenige, das damit übereinstimmt, ist die Shell-Variable "tty". Zugewiesen an `.
Lass es uns tatsächlich benutzen. Da dieses Experiment durch Verbinden von Mac mit SSH durchgeführt wurde, wurde das Pseudo-Terminal ordnungsgemäß angezeigt.
Erstellen Sie einen Befehl "ps" mit den bisher erstellten Funktionen "read_stat" und "get_tty".
.bash
function ps {
echo -e "PID\tTTY\tSTATE\tTIME\tCMD"
for stat in /proc/[1-9]*/stat #Stellen Sie sich ein Verzeichnis vor, das mit einer Nummer beginnt und stat hat
do
read_stat $stat
if [ $tty_nr -ne 0 ] #Nur Prozesse mit Terminals anzeigen
then
get_tty #Holen Sie sich tty
echo -e "${pid}\t${tty}\t${state}\t${time}\t${comm:1:-1}" #Vom Wert von comm()Entfernen
fi
done
}
Hier hat die Shell-Variable comm
eine Zeichenfolge in Klammern, daher entferne ich sie und gebe sie aus ($ {comm: 1: -1}
).
Lass es uns tatsächlich benutzen. Es wurde richtig ausgegeben. Dieses Mal stellte ich auch fest, dass Bash auf dem Monitor ausgeführt wird, der direkt mit dem Raspeltorte verbunden ist, und dessen PID 614 beträgt.
Ich denke, Sie können erkennen, dass Sie mit den integrierten Befehlen von bash alles unerwartet tun können. Wenn ich Zeit habe, möchte ich über Prozessmanagement sprechen (Jobkonzepte, Kill-Befehle, Signale usw.).