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