GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Dumme Bash-Tricks:Verlauf, Wiederverwendung von Argumenten, Dateien und Verzeichnissen, Funktionen und mehr

Als Systemadministrator gehören Shells zum täglichen Betrieb. Shells bieten oft mehr Optionen und Flexibilität als eine grafische Benutzeroberfläche (GUI). Sich täglich wiederholende Aufgaben können einfach durch Skripte automatisiert werden, oder Aufgaben können so geplant werden, dass sie zu bestimmten Zeiten während des Tages ausgeführt werden. Eine Shell bietet eine bequeme Möglichkeit, mit dem System zu interagieren, und ermöglicht es Ihnen, in kürzerer Zeit mehr zu tun. Es gibt viele verschiedene Shells, darunter Bash, zsh, tcsh und PowerShell.

In diesem zweiteiligen Blogbeitrag teile ich einige der Bash-Einzeiler, die ich verwende, um meine Arbeit zu beschleunigen und mehr Zeit zum Kaffeetrinken zu lassen. In diesem ersten Beitrag werde ich den Verlauf, die letzten Argumente, die Arbeit mit Dateien und Verzeichnissen, das Lesen von Dateiinhalten und Bash-Funktionen behandeln. In Teil zwei werde ich Shell-Variablen, den Find-Befehl, Dateideskriptoren und das Ausführen von Operationen aus der Ferne untersuchen.

Verwenden Sie den Verlaufsbefehl

Der history Befehl ist praktisch. history ermöglicht mir zu sehen, welche Befehle ich auf einem bestimmten System ausgeführt habe oder welche Argumente an diesen Befehl übergeben wurden. Ich verwende history um Befehle erneut auszuführen, ohne sich an irgendetwas erinnern zu müssen.

Die Aufzeichnung der letzten Befehle wird standardmäßig in ~/.bash_history. gespeichert Dieser Speicherort kann geändert werden, indem die Shell-Variable HISTFILE geändert wird. Es gibt andere Variablen, wie HISTSIZE (Zeilen, die für die aktuelle Sitzung im Speicher gespeichert werden sollen) und HISTFILESIZE (wie viele Zeilen in der Verlaufsdatei aufbewahrt werden sollen). Wenn Sie mehr über history erfahren möchten , siehe man bash .

Nehmen wir an, ich führe den folgenden Befehl aus:

$> sudo systemctl status sshd

Bash sagt mir, dass der sshd-Dienst nicht läuft, also möchte ich als Nächstes den Dienst starten. Ich hatte seinen Status mit meinem vorherigen Befehl überprüft. Dieser Befehl wurde im history gespeichert , damit ich darauf verweisen kann. Ich führe einfach aus:

$> !!:s/status/start/
sudo systemctl start sshd

Der obige Ausdruck hat folgenden Inhalt:

  • !! - den letzten Befehl aus dem Verlauf wiederholen
  • :s/status/start/ - ersetzt status mit Start

Als Ergebnis wird der sshd-Dienst gestartet.

Als Nächstes erhöhe ich den Standardwert HISTSIZE von 500 auf 5000, indem ich den folgenden Befehl verwende:

$> echo “HISTSIZE=5000” >> ~/.bashrc && source ~/.bashrc

Was ist, wenn ich die letzten drei Befehle in meinem Verlauf anzeigen möchte? Ich gebe ein:

$> history 3
 1002  ls
 1003  tail audit.log
 1004  history 3

Ich führe tail aus auf audit.log durch Bezugnahme auf die Verlaufszeilennummer. In diesem Fall verwende ich Zeile 1003:

$> !1003
tail audit.log
..
..

Stellen Sie sich vor, Sie haben etwas von einem anderen Terminal oder Ihrem Browser kopiert und Sie fügen versehentlich die Kopie (die Sie im Kopierpuffer haben) in das Terminal ein. Diese Zeilen werden im Verlauf gespeichert, was Sie hier nicht möchten. Hier also unset HISTFILE &&beenden ist praktisch

$> unset HISTFILE && exit

oder

$> kill -9 $$

Letztes Argument des vorherigen Befehls referenzieren

Wenn ich Verzeichnisinhalte für verschiedene Verzeichnisse auflisten möchte, kann es sein, dass ich ziemlich oft zwischen den Verzeichnissen wechsle. Es gibt einen netten Trick, mit dem Sie auf das letzte Argument des vorherigen Befehls verweisen können. Zum Beispiel:

$> pwd
/home/username/
$> ls some/very/long/path/to/some/directory
foo-file bar-file baz-file

Im obigen Beispiel /some/very/long/path/to/some/directory ist das letzte Argument des vorherigen Befehls.

Wenn ich cd möchte (Verzeichnis wechseln) zu diesem Ort, gebe ich etwa Folgendes ein:

$> cd $_

$> pwd
/home/username/some/very/long/path/to/some/directory

Verwenden Sie jetzt einfach einen Bindestrich, um dorthin zurückzukehren, wo ich war:

$> cd -
$> pwd
/home/username/

Dateien und Verzeichnisse bearbeiten

Stellen Sie sich vor, ich möchte eine Verzeichnisstruktur erstellen und eine Reihe von Dateien mit unterschiedlichen Erweiterungen in diese Verzeichnisse verschieben.

Zuerst erstelle ich die Verzeichnisse auf einmal:

$> mkdir -v dir_{rpm,txt,zip,pdf}
mkdir: created directory 'dir_rpm'
mkdir: created directory 'dir_txt'
mkdir: created directory 'dir_zip'
mkdir: created directory 'dir_pdf'

Als nächstes verschiebe ich die Dateien basierend auf der Dateierweiterung in jedes Verzeichnis:

$> mv -- *.rpm dir_rpm/
$> mv -- *.pdf dir_pdf/
$> mv -- *.txt dir_txt/
$> mv -- *.zip dir_txt/

Die doppelten Bindestriche -- bedeuten Ende der Optionen. Dieses Flag verhindert, dass Dateien, die mit einem Bindestrich beginnen, als Argumente behandelt werden.

Als nächstes möchte ich alle *.txt-Dateien in *.log-Dateien ersetzen/verschieben, also gebe ich ein:

$> for f in ./*.txt; do mv -v ”$file” ”${file%.*}.log”; done
renamed './file10.txt' -> './file10.log'
renamed './file1.txt' -> './file1.log'
renamed './file2.txt' -> './file2.log'
renamed './file3.txt' -> './file3.log'
renamed './file4.txt' -> './file4.log'

Anstatt den for zu verwenden Schleife oben, kann ich den prename installieren befehlen und das obige Ziel wie folgt erreichen:

$> prename -v 's/.txt/.log/' *.txt
file10.txt -> file10.log
file1.txt -> file1.log
file2.txt -> file2.log
file3.txt -> file3.log
file4.txt -> file4.log

Wenn ich eine Konfigurationsdatei ändere, erstelle ich oft eine Sicherungskopie der Originaldatei, indem ich einen einfachen Kopierbefehl verwende. Zum Beispiel:

$> cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth0.back

Wie Sie sehen können, ist das Wiederholen des gesamten Pfads und das Anhängen von .back an die Datei nicht so effizient und wahrscheinlich fehleranfällig. Es gibt einen kürzeren, saubereren Weg, dies zu tun. Hier kommt es:

$> cp /etc/sysconfig/network-scripts/ifcfg-eth0{,.back}

Sie können verschiedene Überprüfungen von Dateien oder Variablen durchführen. Führen Sie help test aus für weitere Informationen.

Verwenden Sie den folgenden Befehl, um festzustellen, ob eine Datei ein symbolischer Link ist:

$> [[ -L /path/to/file ]] && echo “File is a symlink”

Hier ist ein Problem, auf das ich kürzlich gestoßen bin. Ich wollte mehrere Dateien auf einmal komprimieren/enttarnen. Ohne nachzudenken, tippte ich:

$> tar zxvf *.gz

Das Ergebnis war:

tar: openvpn.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors

Die Tar-Dateien waren:

iptables.tar.gz
openvpn.tar.gz
…..

Warum hat es nicht funktioniert und warum sollte ls -l *.gz stattdessen arbeiten? Unter der Haube sieht es so aus:

$> tar zxvf *.gz

Wird wie folgt transformiert:

$> tar zxvf iptables.tar.gz openvpn.tar.gz
tar: openvpn.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors

Der tar Der Befehl findet voraussichtlich openvpn.tar.gz in iptables.tar.gz. Ich habe das mit einem einfachen for gelöst Schleife:

$> for f in ./*.gz; do tar zxvf "$f"; done
iptables.log
openvpn.log

Ich kann sogar zufällige Passwörter generieren, indem ich Bash verwende! Hier ist ein Beispiel:

$> alphanum=( {a..z} {A..Z} {0..9} ); for((i=0;i<=${#alphanum[@]};i++)); do printf '%s' "${alphanum[@]:$((RANDOM%255)):1}"; done; echo

Hier ist ein Beispiel, das OpenSSL verwendet:

$> openssl rand -base64 12
JdDcLJEAkbcZfDYQ

Eine Datei Zeile für Zeile lesen

Angenommen, ich habe eine Datei mit vielen IP-Adressen und möchte mit diesen IP-Adressen arbeiten. Zum Beispiel möchte ich dig ausführen zum Abrufen von Reverse-DNS-Informationen für die in der Datei aufgeführten IP-Adressen. Ich möchte auch IP-Adressen überspringen, die mit einem Kommentar (# oder Hashtag) beginnen.

Ich werde fileA als Beispiel verwenden. Sein Inhalt ist:

10.10.12.13  some ip in dc1
10.10.12.14  another ip in dc2
#10.10.12.15 not used IP
10.10.12.16  another IP

Ich könnte jede IP-Adresse kopieren und einfügen und dann dig ausführen manuell:

$> dig +short -x 10.10.12.13

Oder ich könnte dies tun:

$> while read -r ip _; do [[ $ip == \#* ]] && continue; dig +short -x "$ip"; done < ipfile

Was ist, wenn ich die Spalten in Datei A tauschen möchte? Zum Beispiel möchte ich IP-Adressen in die Spalte ganz rechts einfügen, damit fileA so aussieht:

some ip in dc1 10.10.12.13
another ip in dc2 10.10.12.14
not used IP #10.10.12.15
another IP 10.10.12.16

Ich führe aus:

$> while  read -r ip rest; do printf '%s %s\n' "$rest" "$ip"; done < fileA

Bash-Funktionen verwenden

Funktionen in Bash unterscheiden sich von denen, die in Python, C, awk oder anderen Sprachen geschrieben wurden. In Bash würde eine einfache Funktion, die ein Argument akzeptiert und "Hallo Welt" ausgibt, so aussehen:

func() { local arg=”$1”; echo “$arg” ; }

Ich kann die Funktion so aufrufen:

$> func foo

Manchmal ruft sich eine Funktion selbst rekursiv auf, um eine bestimmte Aufgabe auszuführen. Zum Beispiel:

func() { local arg="$@"; echo "$arg"; f "$arg"; }; f foo bar

Diese Rekursion wird ewig laufen und viele Ressourcen verbrauchen. In Bash können Sie FUNCNEST verwenden, um die Rekursion zu begrenzen. Im folgenden Beispiel setze ich FUNCNEST=5, um die Rekursion auf fünf zu begrenzen.

func() { local arg="$@"; echo "$arg"; FUNCNEST=5; f "$arg"; }; f foo bar
foo bar
foo bar
foo bar
foo bar
foo bar
bash: f: maximum function nesting level exceeded (5)

Verwenden Sie eine Funktion, um die neueste oder älteste Datei abzurufen

Hier ist eine Beispielfunktion, um die neueste Datei in einem bestimmten Verzeichnis anzuzeigen:

latest_file()
{
  local f latest
  for f in "${1:-.}"/*
    do
      [[ $f -nt $latest ]] && latest="$f"
    done
   printf '%s\n' "$latest"
}

Diese Funktion zeigt die älteste Datei in einem bestimmten Verzeichnis an:

oldest_file()
{
  local f oldest
  for file in "${1:-.}"/*
    do
      [[ -z $oldest || $f -ot $oldest ]] && oldest="$f"
    done
  printf '%s\n' "$oldest"
}

Dies sind nur einige Beispiele dafür, wie Sie Funktionen in Bash verwenden können, ohne andere externe Befehle aufzurufen.

Manchmal erwische ich mich dabei, einen Befehl immer wieder mit vielen Parametern einzugeben. Ein Befehl, den ich oft verwende, ist kubectl (Kubernetes-CLI). Ich bin es leid, diesen langen Befehl auszuführen! Hier ist der ursprüngliche Befehl:

$> kubectl -n my_namespace get pods

oder

$> kubectl -n my_namespace get rc,services

Diese Syntax erfordert, dass ich -n my_namespace manuell einfüge Jedes Mal, wenn ich den Befehl ausführe. Es gibt einen einfacheren Weg, dies mit einer Funktion zu tun:

$> kubectl () { command kubectl -n my_namespace ”$@” ; }

Jetzt kann ich kubectl ausführen ohne -n namespace eingeben zu müssen jedes Mal:

$> kubectl get pods

Ich kann die gleiche Technik auf andere Befehle anwenden.

Abschluss

Dies sind nur einige hervorragende Tricks, die es für Bash gibt. Im zweiten Teil werde ich einige weitere Beispiele zeigen, einschließlich der Verwendung von find und der Remote-Ausführung. Ich ermutige Sie, diese Tricks zu üben, um Ihre Verwaltungsaufgaben über die Befehlszeile einfacher und genauer zu machen.

[ Kostenloser Online-Kurs:Technischer Überblick zu Red Hat Enterprise Linux. ]


Linux
  1. Finden Sie Dateien und Verzeichnisse in Linux wie ein Profi

  2. Weitere dumme Bash-Tricks:Variablen, Suchen, Dateideskriptoren und Remote-Operationen

  3. Finden Sie die größten Dateien und Verzeichnisse in Linux

  4. So erstellen und rufen Sie Funktionen in Bash auf

  5. Linux Dateien und Verzeichnisse löschen

So komprimieren Sie Dateien und Verzeichnisse unter Linux

So synchronisieren Sie Dateien und Verzeichnisse mit Zaloha.sh

Komprimieren und Archivieren von Dateien und Verzeichnissen

Finden Sie Dateien und Verzeichnisse unter Linux ganz einfach

Standarddateien und -verzeichnisse in cPanel

So löschen Sie den Bash-Verlauf in Linux und Mac