Wie kann ich die aktuelle Shell bestimmen, an der ich arbeite?
Wäre die Ausgabe des psBefehls allein ausreichend?
Wie kann dies in verschiedenen Unix-Varianten erfolgen?
Wie kann ich die aktuelle Shell bestimmen, an der ich arbeite?
Wäre die Ausgabe des psBefehls allein ausreichend?
Wie kann dies in verschiedenen Unix-Varianten erfolgen?
Antworten:
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.
echo ${.sh.version}gibt "Bad Substitution" zurück. Siehe meine Lösung oben
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.
ps -ef | awk '$2==pid' pid=$$
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.
psdie möglicherweise nicht verstanden wird, -psodass Sie sie möglicherweise verwenden müssen /bin/ps -p $$.
$$außer denen, fishmit denen Sie sie verwenden müssten ps -p %self.
/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.
readlink /proc/$$/exe
shemuliert wird bash, geben ps -p Ihnen /usr/bin/bashsogar, dass Sie es alssh
Versuchen
ps -p $$ -oargs=
oder
ps -p $$ -ocomm=
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.)
-qanstelle von -p:SHELL=$(ps -ocomm= -q $$)
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; exit 1; fi
#!/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.
Du kannst es versuchen:
ps | grep `echo $$` | awk '{ print $4 }'
Oder:
echo $SHELL
/pattern/ { action }wird es gehen?
$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.
awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$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.
/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.
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
echo 'aaaa' > script; chmod +x script; ./scriptgibt./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 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:
basename $(readlink /proc/$$/exe)
/proc. Nicht die ganze Welt ist eine Linux-Box.
basename $(readlink /proc/$$/exe)zu ls+ sed+ echo.
ash -> /bin/busybox, wird dies / bin / Busybox ergeben.
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}'
}
... und dann einfach ausführen shell.
Es wurde unter Debian und Cygwin getestet.
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.
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.
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.
awk, wann ps -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 )
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/cursh
set -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"; exit 1; }
export PATH
cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
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"; exit 1; }
lsofstr="`lsof -p $ppid`" ||
{ printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }
printf "%s\n" "${lsofstr}" |
LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'
-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
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 arrays
if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
exit 1
fi
;;
*/bash@[123])
echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
exit 1
;;
*)
echo >&2 "This script requires BASH (version 4+) - not regular sh"
echo >&2 "Re-run as \"bash $CMD\" for proper operation"
exit 1
;;
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. :(
sed: invalid option -- 'E'auf Bash 3.2.51 und tcsh 6.15.00
Meine Lösung:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
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).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$ist unzuverlässig. ps -ef | awk -v pid=$$ '$2==pid { print $8 }'ist besser, aber warum nicht einfach verwenden ps -p $$?
Unter Mac OS X (und FreeBSD):
ps -p $$ -axco command | sed -n '$p'
zsh, und es gab mir -bash.
mutt...: -b
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):
$ sh --version
sh: 0: Illegal option --
echo $?
2
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=false
for i in ${shells_array[*]}; do
if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
shell=$i
suited=true
fi
done
echo $shell
}
getshell
Jetzt können Sie verwenden $(getshell) --version.
Dies funktioniert jedoch nur bei KornShell- ähnlichen Shells (ksh).
dash, yashusw. Normalerweise , wenn Sie mit bash, zsh, ksh, was auch immer - Sie sollten über solche Dinge nicht.
kshdie Funktionen meistens eine Teilmenge der bashFunktionen 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.
Bitte benutzen Sie den folgenden Befehl:
ps -p $$ | tail -1 | awk '{print $4}'
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.
echo $SHELLkann 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 :
ps -T $$ | awk 'NR==2{print $NF}'
alternativ sollte das folgende auch funktionieren, wenn pstree verfügbar ist:
pstree | egrep $$ | awk 'NR==2{print $NF}'
!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