bash - übergabe - ssh skript ausführen




Befehle als Eingabe an einen anderen Befehl übergeben(su, ssh, sh usw.) (2)

Ich habe ein Skript, in dem ich einen Befehl starten und dann einige zusätzliche Befehle als Befehle an diesen Befehl übergeben muss. Ich habe es versucht

su
echo I should be root now:
who am I
exit
echo done.

... aber es funktioniert nicht: Die su erfolgreich, aber dann starrt mich die Eingabeaufforderung nur an. Wenn ich an der Eingabeaufforderung exit eingebe, wird das echo und who am i usw. ausgeführt! Und das echo done. wird überhaupt nicht hingerichtet.

Ebenso muss ich dafür über ssh :

ssh remotehost
# this should run under my account on remotehost
su
## this should run as root on remotehost
whoami
exit
## back
exit
# back

Wie löse ich das?

Ich suche nach Antworten, die dies allgemein lösen und die nicht spezifisch für su oder ssh . Es ist beabsichtigt, dass diese Frage für dieses bestimmte Muster canonical wird.


Ein Shell-Skript ist eine Folge von Befehlen. Die Shell liest die Skriptdatei und führt diese Befehle nacheinander aus.

Im Normalfall gibt es hier keine Überraschungen; Ein häufiger Anfängerfehler geht jedoch davon aus, dass einige Befehle von der Shell übernommen werden und die folgenden Befehle in der Skriptdatei anstelle der Shell ausgeführt werden, auf der dieses Skript derzeit ausgeführt wird. Aber so funktioniert es nicht.

Grundsätzlich funktionieren Skripte genau wie interaktive Befehle, aber wie genau sie funktionieren, muss richtig verstanden werden. Interaktiv liest die Shell einen Befehl (von der Standardeingabe), führt diesen Befehl aus (mit der Eingabe von der Standardeingabe), und wenn dies abgeschlossen ist, liest sie einen anderen Befehl (von der Standardeingabe).

Beim Ausführen eines Skripts ist die Standardeingabe weiterhin das Terminal (sofern Sie keine Umleitung verwendet haben), die Befehle werden jedoch aus der Skriptdatei und nicht aus der Standardeingabe gelesen. (Das Gegenteil wäre in der Tat sehr umständlich - jeder read würde die nächste Zeile des Skripts verbrauchen, cat würde den gesamten Rest des Skripts schlürfen und es gäbe keine Möglichkeit, damit zu interagieren!) Die Skriptdatei enthält nur Befehle für die Shell-Instanz, die es ausführt (obwohl Sie natürlich immer noch ein here-Dokument usw. verwenden können, um Eingaben als Befehlsargumente einzubetten).

Mit anderen Worten, diese "missverstandenen" Befehle ( su , ssh , sh , sudo , bash usw.) starten, wenn sie alleine (ohne Argumente) ausgeführt werden, eine interaktive Shell, und in einer interaktiven Sitzung ist das offensichtlich in Ordnung. Aber wenn Sie ein Skript ausführen, ist das oft nicht das, was Sie wollen.

Alle diese Befehle können Befehle auf andere Weise als in einer interaktiven Terminalsitzung annehmen. In der Regel unterstützt jeder Befehl eine Möglichkeit, ihn als Optionen oder Argumente zu übergeben:

su root -c 'who am i'
ssh [email protected] uname -a
sh -c 'who am i; echo success'

Viele dieser Befehle akzeptieren auch Befehle für die Standardeingabe:

printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh [email protected]
printf 'uname -a; who am i; uptime' | sh

Damit können Sie hier auch bequem Dokumente verwenden:

ssh [email protected] <<'____HERE'
    uname -a
    who am i
    uptime
____HERE

sh <<'____HERE'
    uname -a
    who am i
    uptime
____HERE

Bei Befehlen, die ein einzelnes Befehlsargument akzeptieren, kann dieser Befehl sh oder bash mit mehreren Befehlen sein:

sudo sh -c 'uname -a; who am i; uptime'

Im Übrigen benötigen Sie im Allgemeinen keinen expliziten exit da der Befehl ohnehin beendet wird, wenn er das Skript (Befehlsfolge) ausgeführt hat, das Sie zur Ausführung übergeben haben.


answer von :

Es ist wichtig, sich daran zu erinnern, dass der als Here-Document für eine andere Shell formatierte Abschnitt des Skripts in einer anderen Shell mit eigener Umgebung (und möglicherweise sogar auf einer anderen Maschine) ausgeführt wird.

Wenn dieser Block Ihres Skripts eine Parametererweiterung, eine Befehlssubstitution und / oder eine arithmetische Erweiterung enthält, müssen Sie die Here-Document-Funktion der Shell etwas anders verwenden, je nachdem, wo diese Erweiterungen ausgeführt werden sollen.

1. Alle Erweiterungen müssen im Rahmen der übergeordneten Shell durchgeführt werden.

Dann muss das Trennzeichen des vorliegenden Dokuments nicht angegeben werden .

command <<DELIMITER
...
DELIMITER

Beispiel:

#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
    a=1
    mylogin=$(whoami)
    echo a=$a
    echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin

Ausgabe:

a=0
mylogin=leon
a=0
mylogin=leon

2. Alle Erweiterungen müssen im Rahmen der Child-Shell durchgeführt werden.

Dann muss das Trennzeichen des vorliegenden Dokuments angegeben werden.

command <<'DELIMITER'
...
DELIMITER

Beispiel:

#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
    a=1
    mylogin=$(whoami)
    echo a=$a
    echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin

Ausgabe:

a=1
mylogin=root
a=0
mylogin=leon

3. Einige Erweiterungen müssen in der untergeordneten Shell ausgeführt werden, andere - in der übergeordneten.

Dann muss der Begrenzer des Dokuments hier nicht in Anführungszeichen gesetzt sein und Sie müssen die Erweiterungsausdrücke umgehen, die in der untergeordneten Shell ausgeführt werden müssen .

Beispiel:

#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
    a=1
    mylogin=\$(whoami)
    echo a=$a
    echo mylogin=\$mylogin
END
echo a=$a
echo mylogin=$mylogin

Ausgabe:

a=0
mylogin=root
a=0
mylogin=leon




sh