Dutzende Tricks mit der Linux-Shell, die Ihre Zeit sparen könnten



  • Zunächst können Sie diesen Artikel hier auf Russisch lesen.

Eines Abends, als ich das Regieren von regulären Ausdrücken von Jeffrey Friedl las, wurde mir klar, dass selbst wenn Sie über alle Unterlagen und viel Erfahrung verfügen, es viele Tricks geben kann, die von verschiedenen Menschen entwickelt und für sich selbst eingesperrt wurden. Alle Menschen sind unterschiedlich. Und Techniken, die für bestimmte Menschen offensichtlich sind, sind für andere möglicherweise nicht offensichtlich und sehen für die dritte Person wie eine seltsame Magie aus. Übrigens habe ich hier bereits einige solcher Momente beschrieben (auf Russisch) .

Für den Administrator oder den Benutzer ist die Befehlszeile nicht nur ein Tool, das alles kann, sondern auch ein hochgradig angepasstes Tool, das für immer entwickelt werden kann. Kürzlich gab es einen übersetzten Artikel über einige nützliche Tricks in CLI. Ich habe jedoch das Gefühl, dass der Übersetzer nicht genügend Erfahrung mit CLI hat und die beschriebenen Tricks nicht befolgt hat, sodass viele wichtige Dinge übersehen oder missverstanden werden können.

Unter dem Strich - ein Dutzend Tricks in der Linux-Shell aus meiner persönlichen Erfahrung.

Hinweis: Alle Skripte und Beispiele im Artikel wurden so weit wie möglich speziell vereinfacht. Vielleicht finden Sie mehrere Tricks völlig nutzlos - vielleicht ist dies der Grund. Aber teilen Sie auf jeden Fall Ihre Meinung in den Kommentaren!

1. Teilen Sie die Zeichenfolge mit variablen Erweiterungen


Menschen verwenden oft geschnitten oder sogar awk , um einen Teil der Schnur nach Muster oder mit Trennzeichen zu subtrahieren.
Außerdem verwenden viele Leute eine Teilzeichenfolgen-Bash-Operation mit $ {VARIABLE: start_position: length}, die sehr schnell funktioniert.

Bash bietet jedoch eine leistungsstarke Möglichkeit zum Bearbeiten von Textzeichenfolgen mit #, ##,% und %% - es werden Bash-Variablenerweiterungen genannt .
Mit dieser Syntax können Sie das Notwendige nach Muster schneiden, ohne externe Befehle ausführen zu müssen, sodass es sehr schnell funktioniert.

Das folgende Beispiel zeigt, wie die dritte Spalte (Shell) aus der Zeichenfolge abgerufen wird, in der durch Doppelpunkt "Benutzername: Homedir: Shell" getrennte Werte mit cut oder mit variablen Erweiterungen getrennt werden (wir verwenden die *: Maske und den Befehl ##, was bedeutet: cut alle Zeichen links bis zum letzten gefundenen Doppelpunkt):

$ STRING="username:homedir:shell" $ echo "$STRING"|cut -d ":" -f 3 shell $ echo "${STRING##*:}" shell 

Die zweite Option startet den untergeordneten Prozess ( Ausschneiden ) nicht und verwendet überhaupt keine Pipes, was viel schneller funktionieren sollte. Und wenn Sie das Bash-Subsystem in Fenstern verwenden, in denen sich die Rohre kaum bewegen, ist der Geschwindigkeitsunterschied erheblich .

Sehen wir uns ein Beispiel für Ubuntu an - führen Sie unseren Befehl 1000 Mal in einer Schleife aus

 $ cat test.sh #!/usr/bin/env bash STRING="Name:Date:Shell" echo "using cut" time for A in {1..1000} do cut -d ":" -f 3 > /dev/null <<<"$STRING" done echo "using ##" time for A in {1..1000} do echo "${STRING##*:}" > /dev/null done 

Ergebnisse
 $ ./test.sh using cut real 0m0.950s user 0m0.012s sys 0m0.232s using ## real 0m0.011s user 0m0.008s sys 0m0.004s 

Der Unterschied ist mehrere Dutzend Mal!

Das obige Beispiel ist natürlich zu künstlich. Im realen Beispiel arbeiten wir nicht mit einer statischen Zeichenfolge, wir möchten eine reale Datei lesen. Und für den Befehl ' cut ' leiten wir einfach / etc / passwd dorthin um. Im Fall von ## müssen wir eine Schleife erstellen und die Datei mit dem internen Befehl ' read ' lesen . Wer wird diesen Fall gewinnen?

 $ cat test.sh #!/usr/bin/env bash echo "using cut" time for count in {1..1000} do cut -d ":" -f 7 </etc/passwd > /dev/null done echo "using ##" time for count in {1..1000} do while read do echo "${REPLY##*:}" > /dev/null done </etc/passwd done 
Ergebnis
 $ ./test.sh $ ./test.sh using cut real 0m0.827s user 0m0.004s sys 0m0.208s using ## real 0m0.613s user 0m0.436s sys 0m0.172s 
Keine Kommentare =)

Noch ein paar Beispiele:

Extrahieren Sie den Wert nach dem gleichen Zeichen:

 $ VAR="myClassName = helloClass" $ echo ${VAR##*= } helloClass 

Text in runden Klammern extrahieren:

 $ VAR="Hello my friend (enemy)" $ TEMP="${VAR##*\(}" $ echo "${TEMP%\)}" enemy 

2. Bash Autocompletion mit Tab


Das Bash-Completion-Paket ist Teil fast jeder Linux-Distribution. Sie können es in /etc/bash.bashrc oder /etc/profile.d/bash_completion.sh aktivieren, aber normalerweise ist es bereits standardmäßig aktiviert. Im Allgemeinen ist die automatische Vervollständigung einer der ersten praktischen Momente auf der Linux-Shell, die ein Neuling zuerst trifft.

Aber die Tatsache, dass nicht jeder alle Bash-Completion-Funktionen nutzt und meiner Meinung nach völlig vergebens ist. Zum Beispiel weiß nicht jeder, dass die automatische Vervollständigung nicht nur mit Dateinamen funktioniert, sondern auch mit Aliasnamen, Variablennamen, Funktionsnamen und für einige Befehle sogar mit Argumenten. Wenn Sie sich mit Autocomplete-Skripten befassen, bei denen es sich tatsächlich um Shell-Skripte handelt, können Sie sogar Autocomplete für Ihre eigene Anwendung oder Ihr eigenes Skript hinzufügen .
Aber kommen wir zurück zu den Aliasnamen.

Sie müssen keine PATH-Variable bearbeiten oder Dateien im angegebenen Verzeichnis erstellen, um einen Alias ​​auszuführen. Sie müssen sie nur zum Profil oder zum Startskript hinzufügen und von jedem Ort aus ausführen.

Normalerweise verwenden wir Kleinbuchstaben für Dateien und Verzeichnisse in * nix, daher kann es sehr bequem sein, Aliase in Großbuchstaben zu erstellen. In diesem Fall wird die Bash-Vervollständigung Ihren Befehl fast mit einem einzigen Buchstaben erraten :

 $ alias TAsteriskLog="tail -f /var/log/asteriks.log" $ alias TMailLog="tail -f /var/log/mail.log" $ TA[tab]steriksLog $ TM[tab]ailLog 

3. Bash Autocompletion mit Tab - Teil 2


In komplizierteren Fällen möchten Sie wahrscheinlich Ihre persönlichen Skripte in $ HOME / bin ablegen.
Aber wir haben Funktionen in Bash.

Funktionen erfordern keinen Pfad oder separate Dateien. Und (Aufmerksamkeits-) Bash-Vervollständigung funktioniert auch mit Funktionen.

Erstellen wir die Funktion LastLogin in .profile (vergessen Sie nicht, .profile neu zu laden):

 function LastLogin { STRING=$(last | head -n 1 | tr -s " " " ") USER=$(echo "$STRING"|cut -d " " -f 1) IP=$(echo "$STRING"|cut -d " " -f 3) SHELL=$( grep "$USER" /etc/passwd | cut -d ":" -f 7) echo "User: $USER, IP: $IP, SHELL=$SHELL" } 

(Eigentlich ist es nicht wichtig, was diese Funktion tut, es ist nur ein Beispielskript, das wir in das separate Skript oder sogar in den Alias ​​einfügen können, aber die Funktion könnte besser sein) .

In der Konsole (bitte beachten Sie, dass der Funktionsname einen Großbuchstaben enthält, um die Bash-Vervollständigung zu beschleunigen):

 $ L[tab]astLogin User: saboteur, IP: 10.0.2.2, SHELL=/bin/bash 

4.1. Sensible Daten


Wenn Sie vor einem Befehl in der Konsole Leerzeichen einfügen, wird dieser nicht im Befehlsverlauf angezeigt. Wenn Sie also ein einfaches Textkennwort in den Befehl eingeben müssen, ist dies eine gute Möglichkeit, diese Funktion zu verwenden. Schauen Sie sich das folgende Beispiel an und geben Sie "Hallo" ein 2 " wird nicht in der Geschichte angezeigt:

 $ echo "hello" hello $ history 2 2011 echo "hello" 2012 history 2 $ echo "my password secretmegakey" # there are two spaces before 'echo' my password secretmegakey $ history 2 2011 echo "hello" 2012 history 2 

Es ist optional
Es ist normalerweise standardmäßig aktiviert, aber Sie können dieses Verhalten in der folgenden Variablen konfigurieren:

export HISTCONTROL = ignoreboth


4.2. Sensible Daten in Befehlszeilenargumenten


Sie möchten einige Shell-Skripte in git speichern, um sie für mehrere Server freizugeben, oder sie sind möglicherweise Teil des Anwendungsstart-Skripts. Und Sie möchten, dass dieses Skript eine Verbindung zur Datenbank herstellt oder andere Aktionen ausführt, für die Anmeldeinformationen erforderlich sind.

Natürlich ist es eine schlechte Idee, Anmeldeinformationen im Skript selbst zu speichern, da git nicht sicher ist.

Normalerweise können Sie Variablen verwenden, die bereits in den Zielumgebungen definiert wurden, und Ihr Skript enthält nicht die Kennwörter selbst.

Sie können beispielsweise in jeder Umgebung ein kleines Skript mit 700 Berechtigungen erstellen und es mit dem Quellbefehl aus dem Hauptskript aufrufen:

 secret.sh PASSWORD=LOVESEXGOD 

 myapp.sh source ~/secret.sh sqlplus -l user/"$PASSWORD"@database:port/sid @mysqfile.sql 

Aber es ist nicht sicher.

Wenn sich jemand anderes bei Ihrem Host anmelden kann, kann er einfach den Befehl ps ausführen und Ihren sqlplus-Prozess mit den gesamten Befehlszeilenargumenten einschließlich Kennwörtern anzeigen. Daher sollten sichere Tools normalerweise in der Lage sein, Kennwörter / Schlüssel / vertrauliche Daten direkt aus Dateien zu lesen.

Zum Beispiel - Secure SSH hat einfach keine Optionen, um ein Passwort in der Kommandozeile anzugeben. Er kann jedoch den SSH-Schlüssel aus der Datei lesen (und Sie können sichere Berechtigungen für die SSH-Schlüsseldatei festlegen).

Und nicht sichere wget haben eine Option "--password", mit der Sie ein Passwort in der Kommandozeile eingeben können. Und während wget ausgeführt wird, kann jeder den Befehl ps ausführen und das von Ihnen angegebene Passwort anzeigen.

Wenn Sie viele vertrauliche Daten haben und diese über Git steuern möchten, ist die einzige Möglichkeit die Verschlüsselung. Sie geben also in jede Zielumgebung nur das Hauptkennwort und alle anderen Daten ein, die Sie verschlüsseln und an git senden können. Über die openssl-CLI-Schnittstelle können Sie über die Befehlszeile mit verschlüsselten Daten arbeiten. Hier ist ein Beispiel zum Ver- und Entschlüsseln über die Befehlszeile:

Die Datei secret.key enthält den Hauptschlüssel - eine einzelne Zeile:

 $ echo "secretpassword" > secret.key; chmod 600 secret.key 

Verwenden wir aes-256-cbc, um eine Zeichenfolge zu verschlüsseln:

 $ echo "string_to_encrypt" | openssl enc -pass file:secret.key -e -aes-256-cbc -a U2FsdGVkX194R0GmFKCL/krYCugS655yLhf8aQyKNcUnBs30AE5lHN5MXPjjSFML 

Sie können diese verschlüsselte Zeichenfolge in jede in git oder an einem anderen Ort gespeicherte Konfigurationsdatei einfügen - ohne secret.key ist es fast unmöglich, sie zu entschlüsseln.
Um den gleichen Befehl zu entschlüsseln, ersetzen Sie einfach -e durch -d:

 $ echo 'U2FsdGVkX194R0GmFKCL/krYCugS655yLhf8aQyKNcUnBs30AE5lHN5MXPjjSFML' | openssl enc -pass file:secret.key -d -aes-256-cbc -a string_to_encrypt 

5. Der Befehl grep


Alle sollten den Befehl grep kennen. Und sei freundlich mit regulären Ausdrücken. Und oft kann man so etwas schreiben wie:

 tail -f application.log | grep -i error 

Oder sogar so:

 tail -f application.log | grep -i -P "(error|warning|failure)" 

Aber vergessen Sie nicht, dass grep viele wunderbare Möglichkeiten hat. Beispiel: -v, das Ihre Suche zurücksetzt und alle Nachrichten außer "info" anzeigt:

 tail -f application.log | grep -v -i "info" 

Zusätzliches Zeug:

Option -P ist sehr nützlich, da grep standardmäßig einen ziemlich veralteten "grundlegenden regulären Ausdruck:" verwendet und -P PCRE aktiviert, das nicht einmal etwas über Gruppierung weiß.
-i ignoriert den Fall.
--line-buffered parses line sofort, anstatt darauf zu warten, den Standard-4k-Puffer zu erreichen (nützlich für tail -f | grep).

Wenn Sie den regulären Ausdruck gut kennen, können Sie mit --only-matching / -o wirklich großartige Dinge mit dem Schneiden von Text tun. Vergleichen Sie einfach die nächsten beiden Befehle, um die Shell von myuser zu extrahieren:

 $ grep myuser /etc/passwd| cut -d ":" -f 7 $ grep -Po "^myuser(:.*){5}:\K.*" /etc/passwd 

Der zweite Befehl sieht kompilierter aus, führt jedoch nur grep anstelle von grep und cut aus , sodass die Ausführung weniger Zeit in Anspruch nimmt.

6. So reduzieren Sie die Größe der Protokolldatei


Wenn Sie in * nix die Protokolldatei löschen, die derzeit von einer Anwendung verwendet wird, können Sie nicht nur alle Protokolle entfernen, sondern auch verhindern, dass die Anwendung bis zum Neustart neue Protokolle schreibt.

Da der Dateideskriptor nicht den Dateinamen, sondern die iNode-Struktur öffnet und die Anwendung weiterhin in den Dateideskriptor in die Datei schreibt, die keinen Verzeichniseintrag hat, wird diese Datei automatisch gelöscht, nachdem die Anwendung vom Dateisystem gestoppt wurde ( Ihre Anwendung kann dies) Öffnen und schließen Sie die Protokolldatei jedes Mal, wenn Sie etwas schreiben möchten, um ein solches Problem zu vermeiden, dies beeinträchtigt jedoch die Leistung .

So löschen Sie die Protokolldatei, ohne sie zu löschen:

 echo "" > application.log 

Oder wir können den Befehl kürzen verwenden:

 truncate --size=1M application.log 

Erwähnen Sie, dass dieser Befehl zum Abschneiden den Rest der Datei löscht, sodass Sie die neuesten Protokollereignisse verlieren. Überprüfen Sie ein weiteres Beispiel zum Speichern der letzten 1000 Zeilen:

 echo "$(tail -n 1000 application.log)" > application.log 

PS Unter Linux haben wir Standard Service Rotatelog. Sie können Ihre Protokolle zum automatischen Abschneiden / Drehen hinzufügen oder vorhandene Protokollbibliotheken verwenden, die dies für Sie tun können (wie log4j in Java).

7. Watch passt auf dich auf!


Es gibt eine Situation, in der Sie darauf warten, dass ein Ereignis beendet wird. Zum Beispiel, während sich ein anderer Benutzer bei der Shell anmeldet (Sie führen den Befehl who kontinuierlich aus), oder jemand die Datei mit scp oder ftp auf Ihren Computer kopieren sollte und Sie auf den Abschluss warten (ls Dutzende Male wiederholen).

In solchen Fällen können Sie verwenden

 watch <command> 

Standardmäßig wird alle 2 Sekunden mit Vorab-Löschen des Bildschirms ausgeführt, bis Strg + C gedrückt wird. Sie können konfigurieren, wie oft ausgeführt werden soll.

Dies ist sehr nützlich, wenn Sie Live-Protokolle anzeigen möchten.

8. Bash-Sequenz


Es gibt ein sehr nützliches Konstrukt zum Erstellen von Bereichen. Zum Beispiel statt so etwas:

 for srv in 1 2 3 4 5; do echo "server${srv}";done server1 server2 server3 server4 server5 

Sie können Folgendes schreiben:

 for srv in server{1..5}; do echo "$srv";done server1 server2 server3 server4 server5 

Sie können auch den Befehl seq verwenden , um formatierte Bereiche zu generieren. Zum Beispiel können wir seq verwenden , um Werte zu erstellen, die automatisch durch die Breite angepasst werden (00, 01 anstelle von 0, 1):

 for srv in $(seq -w 5 10); do echo "server${srv}";done server05 server06 server07 server08 server09 server10 

Ein weiteres Beispiel mit Befehlssubstitution - Dateien umbenennen. Um den Dateinamen ohne Erweiterung zu erhalten, verwenden wir den Befehl ' basename ':

 for file in *.txt; do name=$(basename "$file" .txt);mv $name{.txt,.lst}; done 

Auch noch kürzer mit '%':

 for file in *.txt; do mv ${file%.txt}{.txt,.lst}; done 

PS Zum Umbenennen der Dateien können Sie das Tool " Umbenennen " verwenden, das viele Optionen bietet.

Ein weiteres Beispiel: Erstellen Sie eine Struktur für ein neues Java-Projekt:

 mkdir -p project/src/{main,test}/{java,resources} 

Ergebnis
 project/ !--- src/ |--- main/ | |-- java/ | !-- resources/ !--- test/ |-- java/ !-- resources/ 

9. Schwanz, mehrere Dateien, mehrere Benutzer ...


Ich habe Multitail erwähnt, um Dateien zu lesen und mehrere Live-Protokolle anzusehen . Es wird jedoch nicht standardmäßig bereitgestellt, und Berechtigungen zum Installieren von Objekten sind nicht immer verfügbar.

Aber Standardschwanz kann es auch:

 tail -f /var/logs/*.log 

Erinnern wir uns auch an Benutzer, die 'tail -f'-Aliase verwenden, um Anwendungsprotokolle zu überwachen.
Mehrere Benutzer können Protokolldateien gleichzeitig mit 'tail -f' anzeigen. Einige von ihnen sind mit ihren Sitzungen nicht sehr genau. Sie könnten aus irgendeinem Grund 'tail -f' im Hintergrund lassen und es vergessen.

Wenn die Anwendung neu gestartet wurde, gibt es diese 'tail-f'-Prozesse, die beobachten, dass nicht vorhandene Protokolldateien mehrere Tage oder sogar Monate hängen bleiben können.

Normalerweise ist es kein großes Problem, aber nicht ordentlich.

Falls Sie zum Überwachen des Protokolls einen Alias ​​verwenden, können Sie diesen Alias ​​mit der Option --pid ändern:

 alias TFapplog='tail -f --pid=$(cat /opt/app/tmp/app.pid) /opt/app/logs/app.log' 

In diesem Fall werden alle Endpunkte automatisch beendet, wenn die Zielanwendung neu gestartet wird.

10. Erstellen Sie eine Datei mit der angegebenen Größe


dd war eines der beliebtesten Tools für die Arbeit mit Block- und Binärdaten. Beispiel: Eine mit Null gefüllte 1-MB-Datei wird erstellt:

 dd if=/dev/zero of=out.txt bs=1M count=10 

Aber ich empfehle die Verwendung von Fallocate :

 fallocate -l 10M file.txt 

Auf Dateisystemen, die die Zuweisungsfunktion unterstützen (xfs, ext4, Btrfs ...), wird fallocate im Gegensatz zum dd-Tool sofort ausgeführt. Zuweisen bedeutet außerdem, dass Blöcke tatsächlich zugewiesen werden und keine Ersatzdatei erstellt wird.

11. xargs


Viele Leute kennen den beliebten Befehl xargs . Aber nicht alle verwenden zwei der folgenden Optionen, die Ihr Skript erheblich verbessern könnten.

Erstens: Sie können eine sehr lange Liste von zu verarbeitenden Argumenten erhalten, die die Befehlszeilenlänge überschreiten kann (standardmäßig ~ 4 kb).

Sie können die Ausführung jedoch mit der Option -n einschränken, sodass xargs den Befehl mehrmals ausführt und jeweils eine bestimmte Anzahl von Argumenten sendet:

 $ # lets print 5 arguments and send them to echo with xargs: $ echo 1 2 3 4 5 | xargs echo 1 2 3 4 5 $ # now let's repeat, but limit argument processing by 3 per execution $ echo 1 2 3 4 5 | xargs -n 3 echo 1 2 3 4 5 

Gehen Sie voran. Das Verarbeiten einer langen Liste kann viel Zeit in Anspruch nehmen, da sie in einem einzelnen Thread ausgeführt wird. Wenn wir jedoch mehrere Kerne haben, können wir xargs anweisen , parallel zu laufen:

 echo 1 2 3 4 5 6 7 8 9 10| xargs -n 2 -P 3 echo 

Im obigen Beispiel weisen wir xargs an, die Liste in 3 Threads zu verarbeiten. Jeder Thread akzeptiert und verarbeitet 2 Argumente pro Ausführung. Wenn Sie nicht wissen, wie viele Kerne Sie haben, können Sie dies mit " nproc " optimieren:

 echo 1 2 3 4 5 6 7 8 9 10 | xargs -n 2 -P $(nproc) echo 

12. schlafen? während? lesen!


Einige Zeit müssen Sie einige Sekunden warten. Oder warten Sie auf Benutzereingaben mit read:

 read -p "Press any key to continue " -n 1 

Sie können dem Lesebefehl jedoch einfach eine Timeout-Option hinzufügen, und Ihr Skript wird für eine bestimmte Anzahl von Sekunden angehalten. Bei einer interaktiven Ausführung kann der Benutzer das Warten jedoch problemlos überspringen.

 read -p "Press any key to continue (auto continue in 30 seconds) " -t 30 -n 1 

Sie können also einfach den Schlafbefehl vergessen.

Ich vermute, dass nicht alle meine Tricks interessant aussehen, aber es schien mir, dass ein Dutzend eine gute Zahl zum Ausfüllen sind.

An dieser Stelle verabschiede ich mich und bin dankbar für die Teilnahme an der Umfrage.

Natürlich kannst du das oben Genannte diskutieren und deine coolen Tricks in den Kommentaren teilen!

Source: https://habr.com/ru/post/de444890/


All Articles