So erkennen Sie, ob ein Skript bezogen wird
Ich habe ein Skript, wo ich nicht wollen, es zu nennen exit
wenn es bezogen werden. Zunächst habe ich aber die Prüfung, ob $0 == bash
aber diese Probleme hat wenn das Skript stammt aus einem anderen Skript, oder wenn der Benutzer Quellen von ksh
. Gibt es einen zuverlässigen Weg, die erkennen, wenn ein Skript bezogen werden?
Kommentar zu dem Problem
Ich hatte ein ähnliches Problem eine Weile zurück und löste es durch die Vermeidung von "exit" in allen Fällen; "kill -INT $$" beendet das Skript sicher in jedem Fall.
InformationsquelleAutor der Frage brianegge | 2010-04-21
Du musst angemeldet sein, um einen Kommentar abzugeben.
Scheint dies tragbar sein, zwischen Bash und Korn:
Eine Zeile vergleichbar zu dieser oder einer Zuordnung wie " pathname="$_" (mit einem späteren test und Aktion) muss auf der ersten Zeile des Skripts oder auf der Zeile nach der shebang (die, wenn verwendet, sollte man zum ksh um für Sie zu arbeiten unter den meisten Umständen).
InformationsquelleAutor der Antwort Dennis Williamson
Wenn Ihr Bash-version kennt die BASH_SOURCE array-Variablen, versuchen Sie so etwas wie:
InformationsquelleAutor der Antwort barroyo
Nach dem Lesen @DennisWilliamson Antwort, gibt es einige Probleme, siehe unten:
Als diese Frage stand für die ksh und bash, es ist ein weiterer Teil in dieser Antwort bezüglich ksh... siehe unten.
Einfach bash Weg,
Lassen Sie uns versuchen (on-the-fly, weil bash könnte ;-):
Benutze ich
source
statt aus.
für die Lesbarkeit (wie.
ist ein alias fürsource
):Beachten Sie, dass die Prozess-Nummer nicht ändern, während der Prozess bleiben bezogen:
Warum nicht verwenden
$_ == $0
VergleichDafür viele Fall, ich fange an, schreiben Sie eine wahr Skript:
Kopieren Sie diese in eine Datei namens
testscript
:Nun konnten wir testen:
Ist das ok.
Ist das ok.
Aber,zum testen ein Skript hinzufügen, bevor
-x
Flagge:Oder verwenden Sie vordefinierte Variablen:
Diese nicht mehr funktionieren.
Bewegen Kommentar vom 5. Zeile 6 geben würde, die mehr lesbar Antwort:
Härter: ksh nun...
Da ich nicht ksh eine Menge, nach einigem Lesen Sie auf der man-Seite, da ist mein versucht:
Kopieren Sie diese in ein
testfile.ksh
:Als führen Sie es zwei mal:
und siehe:
Gibt es einige variable herited in einem bezogen laufen, aber nichts wirklich miteinander verwandt sind...
Könnte man sogar prüfen, dass
$SECONDS
ist in der Nähe0.000
, aber das ist sicher nur Händisch bezogen Fällen...Sie könnten sogar versuchen, zu prüfen, für was Elternteil:
Legen Sie diese in Ihr
testfile.ksh
:Als:
oder
ps ho cmd $PPID
, aber das funktioniert nur für eine Ebene von subsessions...Sorry, ich konnte nicht finden, eine zuverlässige Art und Weise zu tun, dass unter ksh.
InformationsquelleAutor der Antwort F. Hauri
Robuste Lösungen für
bash
,ksh
,zsh
, einschließlich einer Kreuz-shell, plus ein einigermaßen robust POSIX-konforme Lösung:Version angegebenen zahlen sind diejenigen, auf die Funktionalität war überprüft - wahrscheinlich, diese Lösungen funktionieren auf viel früheren Versionen, zu - feedback willkommen.
Mit POSIX-Funktionen, die nur (wie in
dash
, die als/bin/sh
auf Ubuntu), es gibt keine robuste Weg, um zu bestimmen, wenn ein Skript bezogen werden - siehe unten diese Antwort für die beste Annäherung.Einzeiler Folgen - Erklärung weiter unten; das Kreuz-shell-version ist Komplex, aber es sollte funktionieren, robust:
bash (überprüft auf 3.57)
ksh (überprüft auf 93u+)
zsh (überprüft auf 5.0.5) - sicher sein, rufen Sie diese außerhalb der Funktion
Kreuz-shell (bash, ksh, zsh)
[NICHT ROBUST] unter Verwendung von POSIX-Funktionen, die nur: siehe unten
Erklärung:
bash
$BASH_SOURCE
... Enthält IMMER die Skript-Datei argument, ob bezogen oder nicht.$0
...$BASH_SOURCE
bash
für eine nicht-login-shell zu, und-bash
für eine login-shell (wie unter OSX), oder, wenn die Bash aufgerufen wurde, alssh
Analogsh
oder-sh
.$0
.$0
, wie mithilfe derexec
builtin mit der-a
option.ksh
Spezielle variable
${.sh.file}
ist etwas Analog zu$BASH_SOURCE
; beachten Sie, dass${.sh.file}
bewirkt eine syntax-Fehler in der bash, zsh, dash, so sicher sein, um es auszuführen bedingt in multi-shell-Skripte.Im Gegensatz zu bash,
$0
und${.sh.file}
sind NICHT garantiert genau identisch mit der non-sourced Fall, als$0
kann ein relative Weg, während${.sh.file}
ist immer eine voll Weg, so$0
behoben werden muss, um einen vollständigen Pfad vor dem Vergleich.zsh
$ZSH_EVAL_CONTEXT
enthält Informationen über die evaluation Kontext - rufen Sie diese außerhalb der Funktion. Innerhalb einer sourced script['s top-level-Bereich],$ZSH_EVAL_CONTEXT
endet mit:file
.Caveat: in einer Kommando-substitution, zsh hängt
:cmdsubst
, also testen$ZSH_EVAL_CONTEXT
für:file:cmdsubst$
es.Verwendung von POSIX-Funktionen, die nur
Wenn Sie bereit sind, machen bestimmten Annahmen, können Sie eine vernünftig, aber nicht narrensicher denke, ob Sie Ihr Skript bezogen werden, basierend auf wissen, den Dateinamen der Schalen, die möglicherweise bei der Ausführung Ihrer Skripts.
Insbesondere bedeutet dies, dass dieser Ansatz scheitert, wenn das Skript bezogen werden, indem ein anderes script.
Der Abschnitt "so zu behandeln, bezogen auf die Anrufung" in diese Antwort von mir beschreibt die Grenzfälle, die nicht behandelt werden mit POSIX-Funktionen, die nur im detail.
Diese setzt auf das standard-Verhalten von
$0
, diezsh
zum Beispiel hat nicht aufweisen.So, der sicherste Ansatz ist, um kombinieren die robusten, shell-spezifische Methoden, die oben mit einem fallback-Lösung für alle übrigen Muscheln.
Tipp der Hut, um Stéphane Desneux und seine Antwort für die inspiration (transforming mein Kreuz-shell-Anweisung Ausdruck in eine
sh
-kompatibelif
Aussage und dem hinzufügen einer Ereignisprozedur für andere shells).InformationsquelleAutor der Antwort mklement0
Den
BASH_SOURCE[]
Antwort (bash-3.0 und höher) scheint die einfachste, obwohlBASH_SOURCE[]
ist nicht dokumentiert zu arbeiten, die außerhalb einer Funktion Körper (es aktuell passiert, zu arbeiten, sich im Streit mit der man-Seite).Die robuste Art und Weise, wie vorgeschlagen von Wirawan Purwanto, ist zu überprüfen
FUNCNAME[1]
innerhalb einer Funktion:Dann:
Dies ist das äquivalent zu dem Sie die Ausgabe von
caller
die Wertemain
undsource
unterscheiden, die der Anrufer Kontext. MitFUNCNAME[]
speichert Sie erfassen und analysierencaller
Ausgabe. Sie müssen wissen oder berechnen Sie Ihren lokalen Aufruf-Tiefe korrekt zu sein, obwohl. Fälle, wie ein Skript bezogen werden von innerhalb einer anderen Funktion oder ein Skript verursacht array (stack) werden tiefer. (FUNCNAME
ist eine spezielle bash-array-Variablen es sollten zusammenhängende Indizes entsprechend dem call-stack, so lange, wie es noch nieunset
.)(In der bash-4.2 und höher können Sie die einfachere form
${FUNCNAME[-1]}
statt für das Letzte Element im array. Verbessert und vereinfacht Dank Dennis Williamson ' s Kommentar unten).Aber dein problem wie gesagt ist, "ich habe ein Skript, wo ich nicht wollen, es zu nennen 'exit' wenn es bezogen werden". Die gemeinsame
bash
idiom für diese situation ist:Wenn das Skript bezogen werden, dann
return
beenden wird das ursprüngliche Skript und an den Aufrufer zurückgeben.Wenn das Skript ausgeführt wird, dann
return
wird ein Fehler zurückgegeben (umgeleitet), undexit
wird das Skript beendet als normal. Beidereturn
undexit
können einen exit-code, falls erforderlich.Leider funktioniert das nicht in
ksh
(zumindest nicht in der AT&T abgeleitete version, die ich hier habe), es behandeltreturn
als äquivalent zuexit
wenn aufgerufen, außerhalb einer Funktion oder dot-Source-Skript.Aktualisiert: Was Sie kann tun in der zeitgenössischen Versionen von
ksh
ist zu prüfen, die spezielle variable.sh.level
dem Aufruf der Funktion Tiefe. Für ein Skript aufgerufen wird diese zunächst gelöscht werden, für ein dot-sourced script auf 1 gesetzt werden.Dies ist nicht ganz so robust sind wie die bash-version, die Sie aufrufen müssen
issourced()
in der Datei, die Sie testen aus, auf der obersten Ebene oder an eine bekannte Funktion der Tiefe.(Sie könnten auch interessiert sein in dieser code auf github verwendet eine
ksh
Disziplin Funktion und einige debug-trap Tricks zu emulieren, die bashFUNCNAME
array.)Die kanonische Antwort hier: http://mywiki.wooledge.org/BashFAQ/109 bietet auch
$-
als ein weiteres Indiz (aber unvollkommen) von der shell-Zustand.Hinweise:
FUNCNAME[]
aber solange nur das Letzte Element in diesem array ist getestet, es ist keine Zweideutigkeit.pdksh
. Die nächste Sache, die ich finden kann bezieht sich nur aufpdksh
, wobei jede Beschaffung ein script öffnet eine neue Datei-Deskriptor (beginnend mit 10 für das original-Skript). Fast sicher nicht etwas, was Sie wollen zu verlassen...InformationsquelleAutor der Antwort mr.spuratic
TL;DR
Versuchen zum ausführen einer
return
- Anweisung. Wenn das Skript nicht bezogen, wird ein Fehler ausgelöst. Erwischen Sie den Fehler, und fahren, wie Sie benötigen.Setzen Sie diese in eine Datei und nennen Sie, sagen wir, test.sh:
Führen Sie es direkt:
Quelle:
Für mich, das funktioniert auch in der zsh und bash.
Erklärung
Den
return
- Anweisung wird ein Fehler ausgelöst, wenn Sie versuchen, führen Sie es außerhalb der Funktion oder wenn das Skript nicht bezogen. Versuchen Sie, diese von einem shell-prompt ein:Brauchen Sie nicht, um zu sehen, dass Fehler Meldung, so leiten Sie die Ausgabe nach dev/null:
Überprüfen Sie nun die exit-code. 0 bedeutet OK (kein Fehler aufgetreten), 1 bedeutet, dass ein Fehler aufgetreten ist:
Sie auch ausführen wollen, die
return
- Anweisung in einer sub-shell. Wenn diereturn
- Anweisung ausgeführt wird . . . gut . . . zurück. Wenn Sie ausführen, es in einer sub-shell, wird es wieder aus der sub-shell, anstatt der Rückkehr aus Ihrem Skript. Ausführen der sub-shell, wickeln Sie es in$(...)
:Nun, Sie können sehen, der exit-code von der sub-shell, die 1 sein soll, da ein Fehler geworfen wurde innerhalb der sub-shell:
InformationsquelleAutor der Antwort user5754163
Gebe ich ein BASH-spezifische Antwort. Korn-shell, sorry. Angenommen, Ihr Skript name ist
include2.sh
; dann machen Sie eine Funktion innen dieinclude2.sh
genanntam_I_sourced
. Hier ist meine demo-version voninclude2.sh
:Nun versuchen Sie zu ausführen es in vielerlei Hinsicht:
Damit dies funktioniert, ohne Ausnahme, und es ist nicht mit der spröden
$_
Zeug. Dieser trick nutzt die BASH - introspection facility, D. H. built-in VariablenFUNCNAME
undBASH_SOURCE
; siehe deren Dokumentation in der bash-Manpage.Nur zwei caveat:
1) der Aufruf zu
am_I_called
muss stattfinden in das ursprüngliche Skript, aber nicht innerhalb jede Funktion, damit${FUNCNAME[1]}
gibt etwas anderes. Ja...Sie haben könnten, überprüft${FUNCNAME[2]}
-- aber Sie nur machen Ihr das Leben schwer.2) Funktion
am_I_called
muss Wohnsitz in das ursprüngliche Skript, wenn Sie herausfinden möchten, was den Namen der Datei enthalten.InformationsquelleAutor der Antwort Wirawan Purwanto
Ich würde gern vorschlagen, eine kleine Korrektur zu Dennis' sehr hilfreiche Antwort, zu machen, leicht tragbar, hoffe ich:
weil
[[
ist nicht erkannt durch die (etwas anal retentive IMHO) Debian POSIX-kompatible shelldash
. Auch die, die man brauchen kann die Angebote zum Schutz vor Dateinamen, die Leerzeichen enthalten, wieder in, sagte shell.InformationsquelleAutor der Antwort user354193
Diese Werke später im Skript und muss nicht davon abhängen, _ - variable:
oder
InformationsquelleAutor der Antwort jim mcnamara
$_
ist ziemlich spröde. Sie haben, um es zu überprüfen, wie das erste, was Sie tun, in das Skript. Und selbst dann ist es nicht garantiert ist, enthält den Namen der shell (wenn sourced) oder den Namen des Skripts (wenn ausgeführt).Zum Beispiel, wenn der Benutzer hat
BASH_ENV
, dann an der Spitze ein Skript$_
enthält den Namen der zuletzt ausgeführte Befehl in dieBASH_ENV
Skript.Der beste Weg, die ich gefunden habe, ist die Verwendung
$0
wie diese:Leider, dieser Weg funktioniert nicht out of the box in zsh aufgrund der
functionargzero
option, mehr zu tun als der name vermuten lässt, und wird standardmäßig aktiviert.Um dies zu umgehen, lege ich
unsetopt functionargzero
in meinem.zshenv
.InformationsquelleAutor der Antwort Mikel
FWIW, nach der Lektüre all die anderen Antworten, kam ich auf folgende Lösung für mich:
Dies funktioniert für alle Skripte, die start mit
#!/bin/bash
aber kann bezogen werden von verschiedenen Muscheln als gut.Dieses Skript Rezept hat folgende Eigenschaften:
bash
,main
genannt wird.bash
,main
wird nur aufgerufen, wenn der aufrufende Skript, das zufällig den gleichen Namen. (Zum Beispiel, wenn es Quellen selbst.)bash
,main
ist nicht genannt.bash
,main
ist nicht genannt.Wenn bewertet von
bash
miteval
(eval "`cat script`"
alle Anführungszeichen sind wichtig!) der kommt nicht direkt von der Kommandozeile, diese Anrufemain
. Für alle anderen Varianten voneval
,main
ist nicht genannt.Wenn
main
ist nicht genannt, es zurücktrue
($?=0
).Somit, mit Ausnahme für einige unwahrscheinlich Ecke Fällen
main
wird nur aufgerufen, wenn das Skript ausgeführt wird, den üblichen Weg. Normalerweise ist dies, was Sie wollen, vor allem, weil Sie nicht Komplex, schwer zu verstehen code.Als
BASH_SOURCE
kann nicht gelöscht werden inbash
, aber in allen anderen shells, diese auch ins edge-Fall, woBASH_SOURCE
passiert, festgelegt werden, um$0
., Warum ich denke, das ist eine gute Allgemeine Methode zur Lösung der Herausforderung
Wenn Sie etwas haben, die bezogen werden können, die von mehreren Schalen, es muss kompatibel sein. Allerdings (Lesen der anderen Antworten), , da es keine portable Möglichkeit zum erkennen der
source
ing, müssen Sie die Regeln ändern.Durch das erzwingen, dass das Skript ausgeführt werden muss
/bin/bash
Sie genau dies tun.Diese löst alle Fälle, aber folgende in welchem Fall das Skript nicht ausgeführt werden kann direkt:
/bin/bash
ist nicht installiert oder disfunctional (ich. E. in einer boot-Umgebung)curl https://example.com/script | $SHELL
wo$SHELL
ist nichtbash
Aber ich kann mir nicht denken, über alle realen Grund, wo Sie Sie brauchen, und auch die Fähigkeit, eine Quelle, die genau das gleiche Skript parallel! In der Regel können Sie wickeln Sie es, so dass das Skript immer bezogen. Führen Sie dann die
main
von hand. So:sh -c '. script && main'
echo 'eval "`curl https://example.com/script`" && main' | $SHELL
Hinweis
Diese Antwort wäre nicht möglich gewesen ohne die Hilfe von allen die anderen Antworten! Auch noch die falschen lieben, die mir dieses posting.
InformationsquelleAutor der Antwort Tino
Folgte ich mklement0 kompakten Ausdruck.
Das ist ordentlich, aber ich merkte, dass es ausfallen kann bei ksh beim Aufruf als diese:
(es denkt, es ist sourced und es ist nicht, weil es führt eine subshell)
Aber der Ausdruck, um dies zu erkennen:
Auch, selbst wenn der Ausdruck ist kompakt, die syntax ist nicht kompatibel mit allen Hüllen.
So beendete ich mit dem folgenden code, der funktioniert bei bash,zsh,dash und ksh
Fühlen Sie sich frei, um den exotischen Muscheln Unterstützung 🙂
InformationsquelleAutor der Antwort Stéphane Desneux
Ich glaube nicht, dass es eine portable Möglichkeit, dies zu tun in beiden ksh und bash. In der bash könnte man erkennen, es mit
caller
Ausgang, aber ich glaube nicht, dass es existiert, entspricht in der ksh.InformationsquelleAutor der Antwort Michal Čihař
Brauchte ich einen one-liner, der funktioniert auf [mac, linux] mit der bash.version >= 3 und keine der Antworten, die die Rechnung passen.
InformationsquelleAutor der Antwort Karsten
Direkt auf den Punkt: müssen Sie bewerten, wenn die variable "$0" gleich den Namen Ihrer Shell.
Wie diese:
, Die über die SHELL:
Über QUELLE:
Es ist ziemlich schwierig, eine 100% portable Weg, erkennen, wenn ein Skript Quelle wurde oder nicht.
Bezüglich meiner Erfahrung (7 Jahre mit Shellscripting), der einzige sichere Weg (nicht abhängig von Umgebungsvariablen mit PIDs und so weiter, das ist nicht sicher, aufgrund der Tatsache, dass es etwas VARIABLE), man soll:
Beide Optionen werden nicht automatisch skaliert, aber es ist der sicherere Weg.
Zum Beispiel:
, wenn Sie Quellcode ein Skript über eine SSH-session, wird der Wert zurückgegeben, der durch die variable "$0" (bei Verwendung Quelle), ist -bash.
ODER
InformationsquelleAutor der Antwort ivanleoncz