Das Testen auf bestimmte Funktionen (z. B. wird es !ersetzt?) Ist wahrscheinlich portabler als das Finden des Namens der Shell. Lokale Gewohnheit könnte Sie etwas ausführen lassen, /bin/shdas tatsächlich Asche, Bindestrich, Bash usw. sein könnte
msw
1
@msw: Scheint ein guter Kommentar zu sein, außer dass ich mich frage "wie?".
Nobar
Es scheint, dass es keine einfache Antwort auf diese Frage gibt. Wenn wir die Shell nicht abfragen können , ist es möglicherweise besser, immer die Shell anzugeben . Ich bin mir nicht sicher, ob dies immer möglich ist, aber vielleicht ist es einfacher zu erreichen, als die Leute allgemein annehmen.
@Aniket, nicht so viel Hilfe, wie Sie vielleicht denken - das interessiert nur interaktive Shell-Prozesse.
Toby Speight
Antworten:
793
Es gibt drei Ansätze, um den Namen der ausführbaren Datei der aktuellen Shell zu ermitteln:
Bitte beachten Sie, dass alle drei Ansätze getäuscht werden können, wenn die ausführbare Datei der Shell ist /bin/sh, aber es ist bashzum Beispiel wirklich eine Umbenennung (was häufig vorkommt).
Daher wird Ihre zweite Frage, ob die psAusgabe funktioniert, mit " nicht immer " beantwortet .
echo $0 - gibt den Programmnamen aus ... der im Fall der Shell die eigentliche Shell ist.
ps -ef | grep $$ | grep -v grep- Hiermit wird nach der aktuellen Prozess-ID in der Liste der ausgeführten Prozesse gesucht. Da der aktuelle Prozess die Shell ist, wird sie eingeschlossen.
Dies ist nicht 100% zuverlässig, da Sie möglicherweise andere Prozesse haben, deren psAuflistung dieselbe Nummer wie die Prozess-ID der Shell enthält, insbesondere wenn diese ID eine kleine Zahl ist (wenn die PID der Shell beispielsweise "5" ist, werden möglicherweise Prozesse aufgerufen "java5" oder "perl5" in derselben grepAusgabe!). Dies ist das zweite Problem beim "ps" -Ansatz, da man sich nicht auf den Shell-Namen verlassen kann.
echo $SHELL- Der Pfad zur aktuellen Shell wird als SHELLVariable für jede Shell gespeichert . Die Einschränkung für diesen Fall ist, dass Sie stattdessen den Wert Ihrer Anmeldeshell erhalten, wenn Sie eine Shell explizit als Unterprozess starten (z. B. nicht Ihre Anmeldeshell). Wenn dies möglich ist, verwenden Sie den Ansatz psoder $0.
Wenn die ausführbare Datei jedoch nicht mit Ihrer tatsächlichen Shell übereinstimmt (z. B. /bin/shbash oder ksh), benötigen Sie Heuristiken. Hier sind einige Umgebungsvariablen, die für verschiedene Schalen spezifisch sind:
$version ist auf tcsh eingestellt
$BASH ist auf Bash gesetzt
$shell (Kleinbuchstaben) wird in csh oder tcsh auf den tatsächlichen Shell-Namen gesetzt
$ZSH_NAME ist auf zsh gesetzt
ksh hat $PS3und $PS4gesetzt, während die normale Bourne-Shell ( sh) nur hat $PS1und $PS2setzt. Dies scheint im Allgemeinen wie die am schwersten zu unterscheiden - den einzigen Unterschied in der gesamten Reihe von Umgebungsvariablen zwischen shund kshwir haben auf Solaris boxt installiert ist $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, und $TMOUT.
ps -p $$wie Matthew Slattery betont. Für ksh: echo $KSH_VERSIONoder echo ${.sh.version}.
Bis auf weiteres angehalten.
@Dennish - mein ksh hat momentan keine KSH_VERSION gesetzt. und echo ${.sh.version}gibt "Bad Substitution" zurück. Siehe meine Lösung oben
DVK
3
" ps -ef | grep …... Dies ist nicht 100% zuverlässig als ..." Die Verwendung eines einfachen regulären Ausdrucks über egrepoder grep -ekann die Zuverlässigkeit auf 100% für alle Zwecke und Zwecke erhöhen : ps -ef | egrep "^\s*\d+\s+$$\s+". Das ^stellt sicher, dass wir am Anfang der Zeile beginnen, dass die \d+UID aufgefressen wird, dass $$die PID übereinstimmt und dass \s*und \s+Leerzeichen zwischen den anderen Teilen berücksichtigt und sichergestellt werden.
Slipp D. Thompson
2
@ SlippD.Thompson funktionierte nicht in GNU / Linux. Aber das scheint zu funktionieren:ps -ef | awk '$2==pid' pid=$$
jarno
97
ps -p $$
sollte überall funktionieren, wo die Lösungen involviert sind ps -efund grepfunktionieren (bei jeder Unix-Variante, die POSIX-Optionen für unterstütztps ) und nicht unter den Fehlalarmen leiden, die durch das Suchen nach einer Folge von Ziffern entstehen, die an anderer Stelle erscheinen können.
Einige Shells haben eine eigene integrierte Version, psdie möglicherweise nicht verstanden wird, -psodass Sie sie möglicherweise verwenden müssen /bin/ps -p $$.
Bis auf weiteres angehalten.
12
Alle Muscheln, mit denen ich vertraut bin, verstehen, $$außer denen, fishmit denen Sie sie verwenden müssten ps -p %self.
Bis auf weiteres angehalten.
3
Eigentlich sollten Sie sich nicht auf harte Wege wie verlassen /bin/ps. pskönnte leicht (eigentlich ist es heutzutage ganz normal) eingebaut werden /usr/bin. $(which ps) -p $$ist ein besserer Weg. Natürlich funktioniert dies nicht bei Fischen und möglicherweise einigen anderen Muscheln. Ich denke, es ist (which ps) -p %selfin Fisch.
Aron Cederholm
1
In einigen minimalen Systemen wie einem Debian-Slim-Docker-Container ist ps möglicherweise nicht vorhanden. In diesem Fall funktioniert dieser Ansatz immer noch:readlink /proc/$$/exe
mxmlnkn
Wenn Ihr von shemuliert wird bash, geben ps -p Ihnen /usr/bin/bashsogar, dass Sie es alssh
Dies ist eine schöne kurze. Ich habe mich benutzt ps -o fname --no-headers $$.
Anne van Rossum
Vielen Dank. Ich fand dies die beste Option in einem Skript, um Bash-spezifische Befehle zu schützen test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (Die nächste Zeile in meinem Skript hat das Äquivalent für csh.)
craq
1
Ich habe festgestellt, dass wenn Sie dies innerhalb einer Subshell tun, dies zu falschen zusätzlichen Zeilen führen kann, indem die PID des Elternteils sowie der tatsächliche Shell-Prozess abgeglichen werden. Dafür benutze ich -qanstelle von -p:SHELL=$(ps -ocomm= -q $$)
Steve
35
Wenn Sie nur sicherstellen möchten, dass der Benutzer ein Skript mit Bash aufruft:
if[!-n "$BASH"];then echo Please run this script $0 with bash;exit1;fi
Dies sollte derjenige sein, der näher an der Spitze liegt. Vielen Dank.
Alex Skrypnyk
4
Es sollte nicht näher an der Spitze sein, da es die Frage überhaupt nicht beantwortet. Wenn die Frage "Wie prüfe ich, ob das Skript unter Bash läuft" wäre, stimme ich dafür.
David Ferenczy Rogožan
2
@DawidFerenczy - Diese Frage ist das beste Ergebnis, wenn Sie nach dieser Phrase suchen. Auf lange Sicht denke ich, dass es viel wichtiger ist, dass Antworten beantworten, wonach die Leute suchen, als zu beantworten, worum es bei der ursprünglichen Frage ging.
ArtOfWarfare
3
Darüber hinaus ist die Variable $ BASH wird unter tcsh definiert , wenn die tcsh von bash aufgerufen wird
18446744073709551615
Das ist sehr nützlich, danke. Passen Sie es einfach ein wenig an und setzen Sie dies als zweite Zeile nach #!/bin/bash: if [ ! -n "$BASH" ] ;then exec bash $0; fi. Mit dieser Zeile wird das Skript mit bash ausgeführt, auch wenn es mit ksh oder sh gestartet wurde. Mein Anwendungsfall benötigt keine Befehlszeilenargumente, kann aber $0bei Bedarf nachträglich hinzugefügt werden.
Was ist der Sinn von grep, gefolgt von awk, wann /pattern/ { action }wird es gehen?
Jens
# in zshell alias shell = 'echo $ {SHELL: t}'
SergioAraujo
4
$SHELLDie Umgebungsvariable enthält eine Shell, die für einen aktuellen Benutzer als Standard konfiguriert ist. Es spiegelt keine Shell wider, die gerade ausgeführt wird. Es ist auch besser zu verwenden, ps -p $$als $$ wegen falsch positiver Ergebnisse zu greppen.
David Ferenczy Rogožan
Die $ SHELL env. Variable zeigt auf die 'übergeordnete' Shell, wie in der POSIX-Spezifikation angegeben: SHELL Diese Variable soll einen Pfadnamen des vom Benutzer bevorzugten Befehlsspracheninterpreters darstellen. Daher ist der Wert von $ SHELL möglicherweise nicht die aktuelle Shell.
Theo
alle innerhalb awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
go2null
16
$SHELLmuss nicht immer die aktuelle Shell anzeigen. Es gibt nur die Standard-Shell wieder, die aufgerufen werden soll.
Um das oben Gesagte zu testen, sagen wir, es bashist die Standard-Shell, versuchen Sie es echo $SHELLund rufen Sie dann im selben Terminal eine andere Shell auf ( z. B. KornShell (ksh)) und versuchen Sie es $SHELL. In beiden Fällen wird das Ergebnis als Bash angezeigt.
Verwenden Sie Verwenden, um den Namen der aktuellen Shell abzurufen cat /proc/$$/cmdline. Und der Pfad zur ausführbaren Shell von readlink /proc/$$/exe.
ps ist die zuverlässigste Methode. Es ist nicht garantiert, dass die Umgebungsvariable SHELL festgelegt wird, und selbst wenn dies der Fall ist, kann sie leicht gefälscht werden.
+1 $ SHELL ist die Standard-Shell für Programme, die eine erzeugen müssen. Es spiegelt nicht unbedingt die Shell wider, die gerade ausgeführt wird.
Jim Lewis
8
Ich habe einen einfachen Trick, um die aktuelle Shell zu finden. Geben Sie einfach eine zufällige Zeichenfolge ein (was kein Befehl ist). Es wird fehlschlagen und einen "nicht gefundenen" Fehler zurückgeben, aber am Anfang der Zeile wird angezeigt, um welche Shell es sich handelt:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Nicht gut in einem Skript. echo 'aaaa' > script; chmod +x script; ./scriptgibt./script.sh: 1: aaaa: not found
schlank
6
Im Folgenden wird immer die tatsächlich verwendete Shell angegeben - es wird der Name der tatsächlich ausführbaren Datei und nicht der Shell-Name (dh ksh93anstelle von kshusw.) abgerufen. Denn /bin/shes wird die tatsächlich verwendete Shell angezeigt, dh dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
Ich weiß, dass es viele gibt, die sagen, dass die lsAusgabe niemals verarbeitet werden sollte, aber wie hoch ist die Wahrscheinlichkeit, dass Sie eine Shell verwenden, die mit Sonderzeichen benannt oder in einem Verzeichnis mit Sonderzeichen abgelegt ist? Wenn dies immer noch der Fall ist, gibt es viele andere Beispiele dafür, wie man es anders macht.
Wie Toby Speight hervorhob , wäre dies ein angemessener und sauberer Weg, um dasselbe zu erreichen:
Dies ist nur ein Fehler bei allen Unices, die nicht bereitstellen /proc. Nicht die ganze Welt ist eine Linux-Box.
Jens
5
Und wenn Sie sind auf Linux, würden wir es vorziehen , basename $(readlink /proc/$$/exe)zu ls+ sed+ echo.
Toby Speight
1
Dies gibt den Namen der tatsächlichen ausführbaren Datei an , nicht die tatsächliche Shell . Wenn die eigentliche Shell beispielsweise als Busybox-Applet verknüpft ist ash -> /bin/busybox, wird dies / bin / Busybox ergeben.
stepse
6
Ich habe viele verschiedene Ansätze ausprobiert und der beste für mich ist:
ps -p $$
Es funktioniert auch unter Cygwin und kann keine falsch positiven Ergebnisse als PID-Grepping erzeugen. Bei einigen Bereinigungen wird nur ein ausführbarer Name ausgegeben (unter Cygwin mit Pfad):
ps -p $$ | tail -1| awk '{print $NF}'
Sie können eine Funktion erstellen, damit Sie sie sich nicht merken müssen:
# Print currently active shell
shell (){
ps -p $$ | tail -1| awk '{print $NF}'}
Ab meinem Setup (Cygwin | Windows 7) ist Ihre Antwort die beste und ps -p $$ | Schwanz -1 | gawk '{print $ NF}' funktioniert auch von cmd ohne $ bash. Bitte beachten Sie gawk statt awk, da awk nur mit bash funktioniert.
WebComer
@WebComer Sorry, ich bin mir nicht sicher, was du mit " funktioniert auch von cmd ohne $ bash " meinst . Auch wenn Sie von Windows - Ports haben würde ps, tailund gawk, cmd wird nicht definiert , $$wie PID es ist , so dass es auf jeden Fall kann es nicht Arbeit unter der Ebene cmd.
David Ferenczy Rogožan
Warum nicht einfach ps -p$$ -o comm=? POSIX sagt, dass die Angabe aller leeren Header den Header vollständig unterdrückt. Wir scheitern immer noch (wie alle psAntworten), wenn wir von einem direkt ausgeführten Skript (z #!/bin/sh. B. ) bezogen werden.
Toby Speight
5
Meine Variante zum Drucken des übergeordneten Prozesses:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Führen Sie keine unnötigen Anwendungen aus, wenn AWK dies für Sie tun kann.
Warum ein unnötiges ausführen awk, wann ps -p "$$" -o 'comm='kann es für Sie tun?
Toby Speight
5
Es gibt viele Möglichkeiten, die Shell und ihre entsprechende Version herauszufinden. Hier sind einige, die für mich gearbeitet haben.
Einfach
$> echo $ 0 (Gibt Ihnen den Programmnamen. In meinem Fall war die Ausgabe -bash .)
$> $ SHELL (Dies führt Sie in die Shell und in der Eingabeaufforderung erhalten Sie den Namen und die Version der Shell. In meinem Fall bash3.2 $ .)
$> echo $ SHELL (Dies gibt Ihnen einen ausführbaren Pfad. In meinem Fall / bin / bash .)
$> $ SHELL --version (Hier erhalten Sie vollständige Informationen zur Shell-Software mit Lizenztyp.)
Hackischer Ansatz
$> ******* ( Geben Sie eine Reihe von zufälligen Zeichen ein und in der Ausgabe erhalten Sie den Shell-Namen. In meinem Fall -bash: Kapitel2-a-sample-isomorphic-app: Befehl nicht gefunden )
Vorausgesetzt, Sie /bin/shunterstützen den POSIX-Standard und auf Ihrem System ist der lsofBefehl installiert - eine mögliche Alternative zu lsofdiesem Fall pid2path-, können Sie auch das folgende Skript verwenden (oder anpassen), das vollständige Pfade druckt:
#!/bin/sh# cat /usr/local/bin/curshset-eu
pid="$$"set-- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login
unset echo env sed ps lsof awk getconf
# getconf _POSIX_VERSION # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"[ $?-ne 0]&&{ echo "'getconf PATH' failed";exit1;}export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd"1>/dev/null2>&1||{ echo "$cmd not found";exit1;}
awkstr="`echo "$@" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"
ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"["${ppid}"X =""X ]&&{ echo "no ppid found";exit1;}
lsofstr="`lsof -p $ppid`"||{ printf "%s\n""lsof failed""try: sudo lsof -p \`ps -p \$\$ -o ppid=\`";exit1;}
printf "%s\n""${lsofstr}"|
LC_ALL=C awk -v var="${awkstr}"'$NF ~ var {print $NF}'
Das funktioniert bei Fischen! Aber für mich schlägt Bash aufgrund der -iOption (-> Umgebung ignorieren) envin der Zeile fehl , in der Sie prüfen lsof, ob sie verfügbar ist. es schlägt fehl mit: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
hoijui
2
Wenn Sie nur überprüfen möchten, ob Sie (eine bestimmte Version von) Bash ausführen, verwenden Sie am besten die $BASH_VERSINFO Array-Variable. Als (schreibgeschützte) Array-Variable kann sie nicht in der Umgebung festgelegt werden, sodass Sie sicher sein können, dass sie (wenn überhaupt) von der aktuellen Shell stammt.
Da Bash beim Aufrufen als ein anderes Verhalten aufweist sh, müssen Sie auch überprüfen, ob die $BASHUmgebungsvariable mit endet /bash.
In einem Skript, das ich geschrieben habe und das Funktionsnamen mit -(nicht Unterstrich) verwendet und von assoziativen Arrays abhängt (hinzugefügt in Bash 4), habe ich die folgende Überprüfung der Integrität (mit hilfreicher Benutzerfehlermeldung):
case`eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null`in*/bash@[456789])# Claims bash version 4+, check for func-names and associative arraysif!eval"declare -A _ARRAY && func-name() { :; }"2>/dev/null;then
echo >&2"bash $BASH_VERSION is not supported (not really bash?)"exit1fi;;*/bash@[123])
echo >&2"bash $BASH_VERSION is not supported (version 4+ required)"exit1;;*)
echo >&2"This script requires BASH (version 4+) - not regular sh"
echo >&2"Re-run as \"bash $CMD\" for proper operation"exit1;;esac
Sie könnten im ersten Fall die etwas paranoide Funktionsprüfung für Funktionen weglassen und einfach davon ausgehen, dass zukünftige Bash-Versionen kompatibel sind.
Keine der Antworten funktionierte mit fishShell (es hat nicht die Variablen $$oder $0).
Dies funktioniert für mich (getestet auf sh, bash, fish, ksh, csh, true, tcsh, und zsh; openSUSE 13.2):
ps | tail -n 4| sed -E '2,$d;s/.* (.*)/\1/'
Dieser Befehl gibt eine Zeichenfolge wie aus bash. Hier bin ich nur mit ps, tailund sed(ohne GNU extesions, versuchen Sie fügen --posixes zu überprüfen). Dies sind alles Standard-POSIX-Befehle. Ich bin sicher, tailkann entfernt werden, aber mein sedFu ist nicht stark genug, um dies zu tun.
Es scheint mir, dass diese Lösung nicht sehr portabel ist, da sie unter OS X nicht funktioniert. :(
Dies sollte auf verschiedenen Plattformen und Shells portierbar sein. Es wird pswie andere Lösungen verwendet, ist jedoch nicht auf sedoder angewiesen awkund filtert Müll aus den Rohrleitungen und sich psselbst heraus, sodass die Shell immer der letzte Eintrag sein sollte. Auf diese Weise müssen wir uns nicht auf nicht tragbare PID-Variablen verlassen oder die richtigen Zeilen und Spalten auswählen.
Ich habe unter Debian und macOS mit Bash, Z shell ( zsh) und fish getestet (was mit den meisten dieser Lösungen nicht funktioniert, ohne den Ausdruck speziell für fish zu ändern, da eine andere PID-Variable verwendet wird).
Versuchte dies während der Verwendung zsh, und es gab mir -bash.
user137369
Auf meinem System (jetzt), getestet mit Bash und Dash, diese Rückkehr mutt...: -b
F. Hauri
1
Das Abrufen der PID von der Ausgabe von "ps" ist nicht erforderlich, da Sie die entsprechende Befehlszeile für jede PID aus der Verzeichnisstruktur / proc lesen können:
echo $(cat /proc/$$/cmdline)
Das ist jedoch vielleicht nicht besser als nur:
echo $0
Wenn Sie eine andere Shell ausführen möchten, als der Name angibt, sollten Sie die Version unter dem zuvor angegebenen Namen von der Shell anfordern:
<some_shell> --version
sh scheint mit Exit-Code 2 zu scheitern, während andere etwas Nützliches geben (aber ich kann nicht alle überprüfen, da ich sie nicht habe):
Dies ist keine sehr saubere Lösung, aber sie macht, was Sie wollen.
# MUST BE SOURCED..
getshell(){local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
shells_array=(# It is important that the shells are listed in descending order of their name length.
pdksh
bash dash mksh
zsh ksh
sh
)local suited=falsefor i in ${shells_array[*]};doif![-z `printf $shell | grep $i`]&&! $suited;then
shell=$i
suited=truefidone
echo $shell
}
getshell
Jetzt können Sie verwenden $(getshell) --version.
Dies funktioniert jedoch nur bei KornShell- ähnlichen Shells (ksh).
"Dies funktioniert jedoch nur bei ksh-ähnlichen Muscheln." Wollen Sie damit sagen, dass ich die Shell überprüfen muss, bevor ich sie ausführen kann ? Hmm ...
jpaugh
@jpaugh, Listen müssen die von der Shell unterstützt diesen Code Sourcing, die nicht der Fall ist dash, yashusw. Normalerweise , wenn Sie mit bash, zsh, ksh, was auch immer - Sie sollten über solche Dinge nicht.
Theoden8
Sie zählen Bash also als "ksh-like"? Ich habs. Das macht mehr Sinn
jpaugh
@jpaugh, nun, das habe ich gemeint, weil kshdie Funktionen meistens eine Teilmenge der bashFunktionen sind (habe dies jedoch nicht gründlich überprüft).
Theoden8
1
Gehen Sie folgendermaßen vor, um festzustellen, ob Ihre Shell Dash / Bash verwendet.
ls –la /bin/sh::
Wenn das Ergebnis /bin/sh -> /bin/bash==> ist, verwendet Ihre Shell Bash.
Wenn das Ergebnis /bin/sh ->/bin/dash==> ist, verwendet Ihre Shell Dash.
Wenn Sie von Bash zu Dash oder umgekehrt wechseln möchten, verwenden Sie den folgenden Code:
ln -s /bin/bash /bin/sh (Shell in Bash ändern)
Hinweis : Wenn der obige Befehl zu einem Fehler führt, der besagt, dass / bin / sh bereits vorhanden ist, entfernen Sie / bin / sh und versuchen Sie es erneut.
Das erste ist Unsinn, echo $SHELLmacht das , was Sie versuchen, und macht es gut. Die zweite ist ebenfalls nicht gut, da die $SHELLUmgebungsvariable die Standard-Shell für einen aktuellen Benutzer enthält, keine aktuell ausgeführte Shell. Wenn ich zum Beispiel bashals Standard-Shell festgelegt habe, führen Sie zshund aus echo $SHELL, es wird gedruckt bash.
David Ferenczy Rogožan
Sie haben Recht, Dawid Ferenczy. Wir können den Befehl ps verwenden, um die aktuelle Shell zu bestimmen. [# ps -p $$ | Schwanz -1 | awk '{print $ 4}'].
!
ersetzt?) Ist wahrscheinlich portabler als das Finden des Namens der Shell. Lokale Gewohnheit könnte Sie etwas ausführen lassen,/bin/sh
das tatsächlich Asche, Bindestrich, Bash usw. sein könnteAntworten:
Es gibt drei Ansätze, um den Namen der ausführbaren Datei der aktuellen Shell zu ermitteln:
Bitte beachten Sie, dass alle drei Ansätze getäuscht werden können, wenn die ausführbare Datei der Shell ist
/bin/sh
, aber es istbash
zum Beispiel wirklich eine Umbenennung (was häufig vorkommt).Daher wird Ihre zweite Frage, ob die
ps
Ausgabe funktioniert, mit " nicht immer " beantwortet .echo $0
- gibt den Programmnamen aus ... der im Fall der Shell die eigentliche Shell ist.ps -ef | grep $$ | grep -v grep
- Hiermit wird nach der aktuellen Prozess-ID in der Liste der ausgeführten Prozesse gesucht. Da der aktuelle Prozess die Shell ist, wird sie eingeschlossen.Dies ist nicht 100% zuverlässig, da Sie möglicherweise andere Prozesse haben, deren
ps
Auflistung dieselbe Nummer wie die Prozess-ID der Shell enthält, insbesondere wenn diese ID eine kleine Zahl ist (wenn die PID der Shell beispielsweise "5" ist, werden möglicherweise Prozesse aufgerufen "java5" oder "perl5" in derselbengrep
Ausgabe!). Dies ist das zweite Problem beim "ps" -Ansatz, da man sich nicht auf den Shell-Namen verlassen kann.echo $SHELL
- Der Pfad zur aktuellen Shell wird alsSHELL
Variable für jede Shell gespeichert . Die Einschränkung für diesen Fall ist, dass Sie stattdessen den Wert Ihrer Anmeldeshell erhalten, wenn Sie eine Shell explizit als Unterprozess starten (z. B. nicht Ihre Anmeldeshell). Wenn dies möglich ist, verwenden Sie den Ansatzps
oder$0
.Wenn die ausführbare Datei jedoch nicht mit Ihrer tatsächlichen Shell übereinstimmt (z. B.
/bin/sh
bash oder ksh), benötigen Sie Heuristiken. Hier sind einige Umgebungsvariablen, die für verschiedene Schalen spezifisch sind:$version
ist auf tcsh eingestellt$BASH
ist auf Bash gesetzt$shell
(Kleinbuchstaben) wird in csh oder tcsh auf den tatsächlichen Shell-Namen gesetzt$ZSH_NAME
ist auf zsh gesetztksh hat
$PS3
und$PS4
gesetzt, während die normale Bourne-Shell (sh
) nur hat$PS1
und$PS2
setzt. Dies scheint im Allgemeinen wie die am schwersten zu unterscheiden - den einzigen Unterschied in der gesamten Reihe von Umgebungsvariablen zwischensh
undksh
wir haben auf Solaris boxt installiert ist$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
, und$TMOUT
.quelle
ps -p $$
wie Matthew Slattery betont. Fürksh
:echo $KSH_VERSION
oderecho ${.sh.version}
.echo ${.sh.version}
gibt "Bad Substitution" zurück. Siehe meine Lösung obenps -ef | grep …
... Dies ist nicht 100% zuverlässig als ..." Die Verwendung eines einfachen regulären Ausdrucks überegrep
odergrep -e
kann die Zuverlässigkeit auf 100% für alle Zwecke und Zwecke erhöhen :ps -ef | egrep "^\s*\d+\s+$$\s+"
. Das^
stellt sicher, dass wir am Anfang der Zeile beginnen, dass die\d+
UID aufgefressen wird, dass$$
die PID übereinstimmt und dass\s*
und\s+
Leerzeichen zwischen den anderen Teilen berücksichtigt und sichergestellt werden.ps -ef | awk '$2==pid' pid=$$
ps -p $$
sollte überall funktionieren, wo die Lösungen involviert sind
ps -ef
undgrep
funktionieren (bei jeder Unix-Variante, die POSIX-Optionen für unterstütztps
) und nicht unter den Fehlalarmen leiden, die durch das Suchen nach einer Folge von Ziffern entstehen, die an anderer Stelle erscheinen können.quelle
ps
die möglicherweise nicht verstanden wird,-p
sodass Sie sie möglicherweise verwenden müssen/bin/ps -p $$
.$$
außer denen,fish
mit denen Sie sie verwenden müsstenps -p %self
./bin/ps
.ps
könnte leicht (eigentlich ist es heutzutage ganz normal) eingebaut werden/usr/bin
.$(which ps) -p $$
ist ein besserer Weg. Natürlich funktioniert dies nicht bei Fischen und möglicherweise einigen anderen Muscheln. Ich denke, es ist(which ps) -p %self
in Fisch.readlink /proc/$$/exe
sh
emuliert wirdbash
, geben ps -p Ihnen/usr/bin/bash
sogar, dass Sie es alssh
Versuchen
oder
quelle
ps -o fname --no-headers $$
.test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
. (Die nächste Zeile in meinem Skript hat das Äquivalent für csh.)-q
anstelle von-p
:SHELL=$(ps -ocomm= -q $$)
Wenn Sie nur sicherstellen möchten, dass der Benutzer ein Skript mit Bash aufruft:
quelle
#!/bin/bash
:if [ ! -n "$BASH" ] ;then exec bash $0; fi
. Mit dieser Zeile wird das Skript mit bash ausgeführt, auch wenn es mit ksh oder sh gestartet wurde. Mein Anwendungsfall benötigt keine Befehlszeilenargumente, kann aber$0
bei Bedarf nachträglich hinzugefügt werden.Du kannst es versuchen:
Oder:
quelle
/pattern/ { action }
wird es gehen?$SHELL
Die Umgebungsvariable enthält eine Shell, die für einen aktuellen Benutzer als Standard konfiguriert ist. Es spiegelt keine Shell wider, die gerade ausgeführt wird. Es ist auch besser zu verwenden,ps -p $$
als $$ wegen falsch positiver Ergebnisse zu greppen.awk
,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELL
muss nicht immer die aktuelle Shell anzeigen. Es gibt nur die Standard-Shell wieder, die aufgerufen werden soll.Um das oben Gesagte zu testen, sagen wir, es
bash
ist die Standard-Shell, versuchen Sie esecho $SHELL
und rufen Sie dann im selben Terminal eine andere Shell auf ( z. B. KornShell (ksh)) und versuchen Sie es$SHELL
. In beiden Fällen wird das Ergebnis als Bash angezeigt.Verwenden Sie Verwenden, um den Namen der aktuellen Shell abzurufen
cat /proc/$$/cmdline
. Und der Pfad zur ausführbaren Shell vonreadlink /proc/$$/exe
.quelle
/proc
.ps ist die zuverlässigste Methode. Es ist nicht garantiert, dass die Umgebungsvariable SHELL festgelegt wird, und selbst wenn dies der Fall ist, kann sie leicht gefälscht werden.
quelle
Ich habe einen einfachen Trick, um die aktuelle Shell zu finden. Geben Sie einfach eine zufällige Zeichenfolge ein (was kein Befehl ist). Es wird fehlschlagen und einen "nicht gefundenen" Fehler zurückgeben, aber am Anfang der Zeile wird angezeigt, um welche Shell es sich handelt:
quelle
echo 'aaaa' > script; chmod +x script; ./script
gibt./script.sh: 1: aaaa: not found
Im Folgenden wird immer die tatsächlich verwendete Shell angegeben - es wird der Name der tatsächlich ausführbaren Datei und nicht der Shell-Name (dh
ksh93
anstelle vonksh
usw.) abgerufen. Denn/bin/sh
es wird die tatsächlich verwendete Shell angezeigt, dhdash
.Ich weiß, dass es viele gibt, die sagen, dass die
ls
Ausgabe niemals verarbeitet werden sollte, aber wie hoch ist die Wahrscheinlichkeit, dass Sie eine Shell verwenden, die mit Sonderzeichen benannt oder in einem Verzeichnis mit Sonderzeichen abgelegt ist? Wenn dies immer noch der Fall ist, gibt es viele andere Beispiele dafür, wie man es anders macht.Wie Toby Speight hervorhob , wäre dies ein angemessener und sauberer Weg, um dasselbe zu erreichen:
quelle
/proc
. Nicht die ganze Welt ist eine Linux-Box.basename $(readlink /proc/$$/exe)
zuls
+sed
+echo
.ash -> /bin/busybox
, wird dies / bin / Busybox ergeben.Ich habe viele verschiedene Ansätze ausprobiert und der beste für mich ist:
Es funktioniert auch unter Cygwin und kann keine falsch positiven Ergebnisse als PID-Grepping erzeugen. Bei einigen Bereinigungen wird nur ein ausführbarer Name ausgegeben (unter Cygwin mit Pfad):
Sie können eine Funktion erstellen, damit Sie sie sich nicht merken müssen:
... und dann einfach ausführen
shell
.Es wurde unter Debian und Cygwin getestet.
quelle
ps
,tail
undgawk
, cmd wird nicht definiert ,$$
wie PID es ist , so dass es auf jeden Fall kann es nicht Arbeit unter der Ebene cmd.ps -p$$ -o comm=
? POSIX sagt, dass die Angabe aller leeren Header den Header vollständig unterdrückt. Wir scheitern immer noch (wie alleps
Antworten), wenn wir von einem direkt ausgeführten Skript (z#!/bin/sh
. B. ) bezogen werden.Meine Variante zum Drucken des übergeordneten Prozesses:
Führen Sie keine unnötigen Anwendungen aus, wenn AWK dies für Sie tun kann.
quelle
awk
, wannps -p "$$" -o 'comm='
kann es für Sie tun?Es gibt viele Möglichkeiten, die Shell und ihre entsprechende Version herauszufinden. Hier sind einige, die für mich gearbeitet haben.
Einfach
Hackischer Ansatz
$> ******* ( Geben Sie eine Reihe von zufälligen Zeichen ein und in der Ausgabe erhalten Sie den Shell-Namen. In meinem Fall -bash: Kapitel2-a-sample-isomorphic-app: Befehl nicht gefunden )
quelle
Vorausgesetzt, Sie
/bin/sh
unterstützen den POSIX-Standard und auf Ihrem System ist derlsof
Befehl installiert - eine mögliche Alternative zulsof
diesem Fallpid2path
-, können Sie auch das folgende Skript verwenden (oder anpassen), das vollständige Pfade druckt:quelle
-i
Option (-> Umgebung ignorieren)env
in der Zeile fehl , in der Sie prüfenlsof
, ob sie verfügbar ist. es schlägt fehl mit:env -i PATH="${PATH}" type lsof
->env: ‘type’: No such file or directory
Wenn Sie nur überprüfen möchten, ob Sie (eine bestimmte Version von) Bash ausführen, verwenden Sie am besten die
$BASH_VERSINFO
Array-Variable. Als (schreibgeschützte) Array-Variable kann sie nicht in der Umgebung festgelegt werden, sodass Sie sicher sein können, dass sie (wenn überhaupt) von der aktuellen Shell stammt.Da Bash beim Aufrufen als ein anderes Verhalten aufweist
sh
, müssen Sie auch überprüfen, ob die$BASH
Umgebungsvariable mit endet/bash
.In einem Skript, das ich geschrieben habe und das Funktionsnamen mit
-
(nicht Unterstrich) verwendet und von assoziativen Arrays abhängt (hinzugefügt in Bash 4), habe ich die folgende Überprüfung der Integrität (mit hilfreicher Benutzerfehlermeldung):Sie könnten im ersten Fall die etwas paranoide Funktionsprüfung für Funktionen weglassen und einfach davon ausgehen, dass zukünftige Bash-Versionen kompatibel sind.
quelle
Keine der Antworten funktionierte mit
fish
Shell (es hat nicht die Variablen$$
oder$0
).Dies funktioniert für mich (getestet auf
sh
,bash
,fish
,ksh
,csh
,true
,tcsh
, undzsh
; openSUSE 13.2):Dieser Befehl gibt eine Zeichenfolge wie aus
bash
. Hier bin ich nur mitps
,tail
undsed
(ohne GNU extesions, versuchen Sie fügen--posix
es zu überprüfen). Dies sind alles Standard-POSIX-Befehle. Ich bin sicher,tail
kann entfernt werden, aber meinsed
Fu ist nicht stark genug, um dies zu tun.Es scheint mir, dass diese Lösung nicht sehr portabel ist, da sie unter OS X nicht funktioniert. :(
quelle
sed: invalid option -- 'E'
auf Bash 3.2.51 und tcsh 6.15.00Meine Lösung:
Dies sollte auf verschiedenen Plattformen und Shells portierbar sein. Es wird
ps
wie andere Lösungen verwendet, ist jedoch nicht aufsed
oder angewiesenawk
und filtert Müll aus den Rohrleitungen und sichps
selbst heraus, sodass die Shell immer der letzte Eintrag sein sollte. Auf diese Weise müssen wir uns nicht auf nicht tragbare PID-Variablen verlassen oder die richtigen Zeilen und Spalten auswählen.Ich habe unter Debian und macOS mit Bash, Z shell (
zsh
) und fish getestet (was mit den meisten dieser Lösungen nicht funktioniert, ohne den Ausdruck speziell für fish zu ändern, da eine andere PID-Variable verwendet wird).quelle
Von Woher wissen Sie , was Ihre aktuelle Shell ist? .
quelle
grep $$
ist unzuverlässig.ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
ist besser, aber warum nicht einfach verwendenps -p $$
?Unter Mac OS X (und FreeBSD):
quelle
zsh
, und es gab mir-bash
.mutt
...: -bDas Abrufen der PID von der Ausgabe von "ps" ist nicht erforderlich, da Sie die entsprechende Befehlszeile für jede PID aus der Verzeichnisstruktur / proc lesen können:
Das ist jedoch vielleicht nicht besser als nur:
Wenn Sie eine andere Shell ausführen möchten, als der Name angibt, sollten Sie die Version unter dem zuvor angegebenen Namen von der Shell anfordern:
sh
scheint mit Exit-Code 2 zu scheitern, während andere etwas Nützliches geben (aber ich kann nicht alle überprüfen, da ich sie nicht habe):quelle
Dies ist keine sehr saubere Lösung, aber sie macht, was Sie wollen.
Jetzt können Sie verwenden
$(getshell) --version
.Dies funktioniert jedoch nur bei KornShell- ähnlichen Shells (ksh).
quelle
dash
,yash
usw. Normalerweise , wenn Sie mitbash
,zsh
,ksh
, was auch immer - Sie sollten über solche Dinge nicht.ksh
die Funktionen meistens eine Teilmenge derbash
Funktionen sind (habe dies jedoch nicht gründlich überprüft).Gehen Sie folgendermaßen vor, um festzustellen, ob Ihre Shell Dash / Bash verwendet.
ls –la /bin/sh
::Wenn das Ergebnis
/bin/sh -> /bin/bash
==> ist, verwendet Ihre Shell Bash.Wenn das Ergebnis
/bin/sh ->/bin/dash
==> ist, verwendet Ihre Shell Dash.Wenn Sie von Bash zu Dash oder umgekehrt wechseln möchten, verwenden Sie den folgenden Code:
ln -s /bin/bash /bin/sh
(Shell in Bash ändern)Hinweis : Wenn der obige Befehl zu einem Fehler führt, der besagt, dass / bin / sh bereits vorhanden ist, entfernen Sie / bin / sh und versuchen Sie es erneut.
quelle
Und ich habe mir das ausgedacht
quelle
Bitte benutzen Sie den folgenden Befehl:
quelle
echo $SHELL
macht das , was Sie versuchen, und macht es gut. Die zweite ist ebenfalls nicht gut, da die$SHELL
Umgebungsvariable die Standard-Shell für einen aktuellen Benutzer enthält, keine aktuell ausgeführte Shell. Wenn ich zum Beispielbash
als Standard-Shell festgelegt habe, führen Siezsh
und ausecho $SHELL
, es wird gedrucktbash
.echo $SHELL
kann Müll sein:~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Dieser funktioniert gut unter Red Hat Linux (RHEL), MacOS, BSD und einigen AIXs :
alternativ sollte das folgende auch funktionieren, wenn pstree verfügbar ist:
quelle