Wie kann ich die aktuelle Shell ermitteln, an der ich arbeite?
Wäre die Ausgabe des Befehls ps
alleine ausreichend?
Wie kann dies in verschiedenen UNIX-Versionen geschehen?
Es gibt drei Möglichkeiten, um das Name der aktuellen Shell-Programmdatei zu finden:
Bitte beachten Sie, dass alle drei Vorgehensweisen getäuscht werden können, wenn die ausführbare Datei der Shell /bin/sh
lautet, es sich jedoch beispielsweise wirklich um eine umbenannte bash
handelt (was häufig vorkommt).
Somit wird Ihre zweite Frage, ob die Ausgabe von ps
funktioniert, mit "nicht immer" beantwortet.
echo $0
- gibt den Programmnamen aus ... bei Shell handelt es sich um die eigentliche Shell
ps -ef | grep $$ | grep -v grep
- Hiermit wird die aktuelle Prozess-ID in der Liste der ausgeführten Prozesse gesucht. Da der aktuelle Prozess Shell ist, wird er eingeschlossen.
Dies ist nicht 100% zuverlässig, da Sie möglicherweise ANDERE Prozesse haben, deren ps
-Auflistung dieselbe Nummer wie die Prozess-ID von Shell enthält, insbesondere wenn diese ID eine kleine Nummer ist (z. B. wenn die PID von Shell "5" ist) Prozesse mit dem Namen "Java5" oder "Perl5" in derselben grep
Ausgabe!). Dies ist das zweite Problem mit dem "ps" -Ansatz, obgleich es nicht möglich ist, sich auf den Shell-Namen zu verlassen.
echo $Shell
- Der Pfad zur aktuellen Shell wird als Shell
-Variable für eine beliebige Shell gespeichert. Die Einschränkung für diese ist, dass, wenn Sie eine Shell explizit als Unterprozess starten (z. B. es ist nicht Ihre Anmeldeshell), Sie stattdessen den Wert Ihrer Anmeldeshell erhalten. Wenn dies möglich ist, verwenden Sie den Ansatz ps
oder $0
.
Wenn die ausführbare Datei jedoch nicht mit Ihrer tatsächlichen Shell übereinstimmt (z. B. ist /bin/sh
tatsächlich bash oder ksh), benötigen Sie Heuristiken. Hier sind einige Umgebungsvariablen, die für verschiedene Shells 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 $PS3
und $PS4
gesetzt, während normale Bourne Shell (sh
) nur $PS1
und $PS2
gesetzt hat. Dies scheint im Allgemeinen am schwierigsten zu unterscheiden zu sein - der EINZIGE Unterschied zwischen sh
und ksh
, den wir auf Solaris Boxen installiert haben, ist $ERRNO
, $FCEDIT
, $LINENO
, $PPID
, $PS3
, $PS4
, $RANDOM
, $SECONDS
, $TMOUT
.
ps -p $$
sollte überall funktionieren, wo die Lösungen mit ps -ef
und grep
funktionieren (auf jeder Unix-Variante, die POSIX-Optionen für ps
) und wird nicht unter den falschen Positiven leiden, die durch Greifen nach einer Folge von Ziffern eingeführt werden, die an anderer Stelle auftreten können.
Versuchen
ps -p $$ -oargs=
oder
ps -p $$ -ocomm=
Wenn Sie nur sicherstellen möchten, dass der Benutzer das Skript mit bash aufruft, gehen Sie wie folgt vor:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
Du kannst es versuchen:
ps | grep `echo $$` | awk '{ print $4 }'
Oder:
echo $Shell
$Shell
muss nicht immer die aktuelle Shell anzeigen. Es gibt nur die aufzurufende Standard-Shell wieder.
Um dies zu testen, sagen Sie, dass bash
die Standard-Shell ist, versuchen Sie echo $Shell
, gehen Sie dann im selben Terminal in eine andere Shell (z. B. ksh) und versuchen Sie $Shell
das Ergebnis als Bash in beiden Fällen.
Verwenden Sie cat /proc/$$/cmdline
und den Pfad zur Shell, die von readlink /proc/$$/exe
ausgeführt werden kann, um den Namen der aktuellen Shell abzurufen.
ps ist die zuverlässigste Methode. Es kann nicht garantiert werden, dass die Shell envar eingestellt ist, 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 (dies ist kein Befehl). Es wird fehlschlagen und einen "nicht gefundenen" Fehler zurückgeben, aber am Anfang der Zeile wird angegeben, um welche Shell es sich handelt:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Dies gibt immer die tatsächlich verwendete Shell an - erhält den Namen der tatsächlich ausführbaren Datei und nicht den Namen der Shell (dh ksh93
anstelle von ksh
usw.) Für /bin/sh
wird die tatsächlich verwendete Shell angezeigt: dh dash
ls -l /proc/$$/exe | sed 's%.*/%%'
Ich weiß, dass hier viele sagen, dass die Ausgabe von ls
neu verarbeitet werden sollte, aber wie hoch ist die Wahrscheinlichkeit, dass eine von Ihnen verwendete Shell mit Sonderzeichen benannt oder in einem Verzeichnis mit Sonderzeichen platziert wird? Wenn dies immer noch der Fall ist, gibt es hier viele andere Beispiele, die es anders machen.
Ich habe viele verschiedene Ansätze ausprobiert und der beste ist für mich:
ps -p $$
Es funktioniert auch unter Cygwin und kann keine False Positives 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 sich diese nicht merken müssen:
# print currently active Shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... und dann einfach Shell
ausführen.
Getestet unter Debian und Cygwin.
Meine Variante zum Drucken des übergeordneten Prozesses.
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Warum unnötige Anwendungen ausführen, wenn 'awk' dies für Sie erledigen kann?
Vorausgesetzt, Ihr /bin/sh
unterstützt den POSIX-Standard und auf Ihrem System ist der lsof
-Befehl installiert - eine mögliche Alternative zu lsof
könnte in diesem Fall pid2path
sein - Sie können auch ( oder passen Sie das folgende Skript an, das vollständige Pfade ausgibt:
#!/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 "[email protected]" | 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}'
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is.
from http://www.unix.com/unix-dummies-questions-answers/10390-how-do-you-what-your-current-Shell.html
Keine der Antworten funktionierte mit der fish
-Shell (sie enthält keine Variablen $$
oder $0
).
Dies funktioniert für mich (getestet mit 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 einen String wie bash
aus. Ich verwende hier nur ps
, tail
und sed
(ohne GNU Erweiterungen; versuche, --posix
hinzuzufügen, um dies zu überprüfen). Sie alle sind Standard-POSIX-Befehle. Ich bin sicher, dass tail
entfernt werden kann, aber mein sed
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. :(
Es gibt viele Möglichkeiten, die Shell und ihre entsprechende Version herauszufinden. Hier sind einige, die für mich gearbeitet haben.
Geradeaus
Hackish Ansatz
$> ******* (Geben Sie einen Satz zufälliger Zeichen ein, und in der Ausgabe wird der Shell-Name angezeigt. In meinem Fall - bash: chapter2-a-sample-isomorphic- app: Befehl nicht gefunden )
Dies ist keine sehr saubere Lösung, macht aber, was Sie wollen.
Mir ist klar, dass die Antwort in diesem guten alten Jahr 2015 etwas spät ist, aber ...
#MUST BE SOURCED..
getshell() {
local Shell="`ps -p $$ | tail -1 | awk '{print $4}'`"
shells_array=(
# It is important that the shells are listed by the decrease of their length name.
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 $(getshell) --version.
verwenden
Dies funktioniert jedoch nur bei ksh-ähnlichen Shells.
Unter Mac OS X (& FreeBSD):
ps -p $$ -axco command | sed -n '$p'
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 verwendet ps
wie andere Lösungen, aber es ist nicht auf sed
oder awk
angewiesen und filtert Müll aus Piping und ps
selbst heraus, sodass die Shell immer die sein sollte letzter Eintrag. Auf diese Weise müssen wir uns nicht auf nicht portable PID-Variablen verlassen oder die richtigen Zeilen und Spalten auswählen.
Ich habe Debian und MacOS mit bash, 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).
Grepping PID von der Ausgabe von "ps" ist nicht erforderlich, da Sie die entsprechende Befehlszeile für jede PID aus der/proc-Verzeichnisstruktur lesen können:
echo $(cat /proc/$$/cmdline)
Das könnte jedoch nicht besser sein als einfach:
echo $0
Wenn Sie eine andere Shell ausführen möchten, als der Name angibt, können Sie die Version von Shell unter Verwendung des zuvor angegebenen Namens anfordern:
<some_Shell> --version
sh scheint mit Exit-Code 2 zu scheitern, während andere etwas Nützliches angeben (aber ich kann nicht alle verifizieren, da ich sie nicht habe):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Führen Sie die folgenden Schritte aus, um festzustellen, ob Ihre Shell DASH/BASH verwendet.
1) ls –la/bin/sh, wenn das Ergebnis / bin/sh ->/bin/bash ==> Dann 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 zu 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.
Wenn Sie nur überprüfen möchten, ob Sie Bash (eine bestimmte Version von Bash) ausführen, verwenden Sie am besten die Array-Variable $BASH_VERSINFO
. 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 jedoch ein anderes Verhalten aufweist, wenn es als sh
aufgerufen wird, müssen Sie auch überprüfen, ob die Umgebungsvariable $BASH
mit /bash
endet.
In einem Skript, das ich geschrieben habe und das Funktionsnamen mit -
(kein Unterstrich) verwendet und das 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 [email protected]${BASH_VERSINFO[0]}' 2>/dev/null` in
*/[email protected][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
;;
*/[email protected][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 die etwas paranoide Funktionsprüfung für Features im ersten Fall weglassen und einfach davon ausgehen, dass zukünftige Bash-Versionen kompatibel wären.
Bitte verwenden sie unten befehl:
# ps -p $$ | tail -1 | awk '{print $4}'