[LINUX] sudo rm -rf / * Erstellt den Befehl ps mit Wrackteilen neu

1. Zuallererst

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. スクリーンショット 2020-03-23 17.57.34.png 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

2 Vorbereitung

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.

2.1 ls Befehl

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. スクリーンショット 2020-03-23 18.28.46.png 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. スクリーンショット 2020-03-23 20.56.34.png 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.

2.2 Befehl cat

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 den Endstatus des Befehls. Zum Beispiel:

.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. スクリーンショット 2020-03-23 23.32.17.png

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.

2.3 Fertigstellung

Außerdem kann sudo rm -rf / * möglicherweise nicht gut mit tab abgeschlossen werden. スクリーンショット 2020-03-23 18.01.52.png ↓ Tab-Eingabe スクリーンショット 2020-03-23 18.01.44.png 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. スクリーンショット 2020-03-24 13.30.56.png 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

3 Erstellen eines ps-Befehls

Lassen Sie uns nun den Befehl ps erstellen. Beginnen Sie mit einer Beschreibung des Verzeichnisses / proc, das Prozessinformationen enthält.

3.1 / proc Verzeichnis

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. スクリーンショット 2020-03-23 20.57.53.png 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 $$". スクリーンショット 2020-03-23 21.00.24.png Darin befindet sich eine Datei namens "stat", die Informationen über den Prozess enthält. スクリーンショット 2020-03-23 21.01.02.png Fangen wir von vorne an.

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. スクリーンショット 2020-03-23 21.29.16.png 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.

3.2 Gerätedatei

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

スクリーンショット 2020-03-23 22.59.37.png

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. スクリーンショット 2020-03-23 23.13.15.png Da dieses Experiment durch Verbinden von Mac mit SSH durchgeführt wurde, wurde das Pseudo-Terminal ordnungsgemäß angezeigt.

3.3 Erstellen eines ps-Befehls

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. スクリーンショット 2020-03-23 23.11.26.png 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.

Am Ende

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.).

Recommended Posts

sudo rm -rf / * Erstellt den Befehl ps mit Wrackteilen neu
ps Befehl "wchan"