Warum wird systemctl \ {restart, status} \ sshd \ nicht ausgeführt? Arbeit?

14

Die Ausgabe des obigen Befehls bei Weitergabe durch Echo lautet:

# echo systemctl\ {restart,status}\ sshd\;
systemctl restart sshd; systemctl status sshd;

Auch wenn ich die Ausgabe in das Terminal einfüge, funktioniert der Befehl. Aber wenn ich versuche, den Befehl direkt auszuführen, erhalte ich:

# systemctl\ {restart,status}\ sshd\;
bash: systemctl restart sshd;: command not found...

Ich habe zwei Fragen..

  1. Wie genau heißt diese Substitutions- und Expansionsmethode? (Damit ich es erforschen und mehr darüber erfahren kann und wie man es richtig benutzt).
  2. Was habe ich hier falsch gemacht? Warum funktioniert es nicht?
Somenath Sinha
quelle

Antworten:

26

Dies ist eine Form der Klammererweiterung in der Shell. Die Idee der Klammererweiterung ist richtig, aber die Art und Weise, wie sie verwendet wurde, ist hier falsch. Wann wolltest du tun:

systemctl\ {restart,status}\ sshd\;

Die Shell interpretiert systemctl restart sshd;einen langen Befehl und versucht, ihn auszuführen. Sie konnte keine Binärdatei finden, um ihn auf diese Weise auszuführen. Denn zu diesem Zeitpunkt versucht die Shell, die Elemente in der Befehlszeile mit einem Token zu versehen, bevor der vollständige Befehl mit Argumenten erstellt wird - dies ist jedoch noch nicht geschehen.

Für solche bekannten Expansionswerte können Sie verwenden evalund sind dennoch sicher. Stellen Sie jedoch sicher, was Sie damit zu erweitern versuchen.

eval systemctl\ {restart,status}\ sshd\;

Aber ich würde stattdessen lieber eine Schleife mit verwenden for, anstatt zu versuchen, einen Einzeiler zu schreiben, oder Folgendes zu verwenden eval:

for action in restart status; do
    systemctl "$action" sshd
done
Inian
quelle
19

Dies wird als Klammererweiterung bezeichnet (wie das Tag angibt).

Was habe ich hier falsch gemacht? Warum funktioniert es nicht?

Betrachten Sie die Schritte zum Lesen und Ausführen einer Befehlszeile in Bash (zum Beispiel):

  1. liest eine Zeile
  2. Parst einen möglicherweise zusammengesetzten Befehl in einfache Komponentenbefehle
  3. Führt verschiedene Erweiterungen der einfachen Befehle durch (Klammererweiterung, Wortteilung, Globbing usw.)
  4. führt dann die einfachen Befehle aus (wobei andere Stufen der Übersichtlichkeit halber weggelassen wurden).

Was Sie versuchen, ist Affekt (2) von (3). Die Aufteilung basierend auf ;befindet sich in Stufe (2), wenn zusammengesetzte Befehle analysiert werden. Zu dem Zeitpunkt, an dem (3) für die Klammererweiterung ausgeführt wird, ist es bereits zu spät, einen zusammengesetzten Befehl zu erstellen.

muru
quelle
6

Die erste Zeile

echo systemctl\ {restart,status}\ sshd\;

erweitere als 3 Token

  • Echo
  • systemctl restart sshd;
  • systemctl status sshd;

Geben Sie dann die letzten beiden Token als Echo aus, und es sieht in Ordnung aus.

ebenfalls die zweite Zeile

systemctl\ {restart,status}\ sshd\;

expandiert als 2 Spielmarken

  • systemctl restart sshd;
  • systemctl status sshd;

und Bash versuchen, nach einer ausführbaren Datei zu suchen, systemctl restart sshd;die sie nicht finden konnte.

Vielleicht möchten Sie Ihre Reise auf der dunklen Seite beginnen, indem Sie sich eval systemctl\ {restart,status}\ sshd\;vor dem Unerwarteten hüten.

Archemar
quelle
die lösung wäre also worttrennung, oder? Wie geht das?
Somenath Sinha