Comment puis-je déterminer le Shell actuel sur lequel je travaille?
La sortie de la commande ps
suffira-t-elle?
Comment cela peut-il être fait dans différentes versions d'UNIX?
Il existe 3 méthodes pour trouver le nom de l'exécutable du shell actuel:
Veuillez noter que les trois approches peuvent être trompées si l'exécutable du shell est /bin/sh
mais qu'il s'agit bien d'un bash
renommé, par exemple (ce qui arrive fréquemment).
Ainsi, votre deuxième question de savoir si la sortie de ps
fera est résolue par "pas toujours".
echo $0
- affichera le nom du programme ... qui, dans le cas de Shell, correspond au shell
ps -ef | grep $$ | grep -v grep
- Ceci recherchera l'ID de processus actuel dans la liste des processus en cours d'exécution. Comme le processus actuel est Shell, il sera inclus.
Ce n’est pas fiable à 100%, car vous pourriez avoir d’AUTRES processus dont la liste ps
inclut le même numéro que l’ID de processus de Shell, en particulier si cet ID est un petit # (par exemple, si le PID de Shell est "5", vous pouvez trouver processus appelés "Java5" ou "Perl5" dans la même sortie grep
!!). C’est le deuxième problème de l’approche "ps", en plus de ne pas pouvoir compter sur le nom du shell.
echo $Shell
- Le chemin d'accès au shell actuel est stocké sous forme de variable Shell
pour tout shell. La mise en garde pour celui-ci est que si vous lancez un Shell explicitement en tant que sous-processus (par exemple, ce n'est pas votre Shell de connexion), vous obtiendrez la valeur de votre Shell de connexion. Si cela est possible, utilisez l'approche ps
ou $0
.
Si, toutefois, l'exécutable ne correspond pas à votre shell actuel (par exemple, /bin/sh
est en réalité bash ou ksh), vous avez besoin d'une heuristique. Voici quelques variables environnementales spécifiques à différents types de coques:
$version
est défini sur tcsh
$BASH
est réglé sur bash
$Shell
(minuscule) est défini sur le nom du shell dans csh ou tcsh
$ZSH_NAME
est défini sur zsh
ksh a $PS3
et $PS4
, alors que Bourne Shell normal (sh
) n'a que $PS1
et $PS2
. Cela semble généralement être le plus difficile à distinguer - la SEULE différence entre un ensemble de variables d’environnement entre sh
et ksh
que nous avons installées sur le boîtier Solaris est $ERRNO
, $FCEDIT
, $LINENO
, $PPID
, $PS3
, $PS4
, $RANDOM
, $SECONDS
, $TMOUT
.
ps -p $$
devrait fonctionner n'importe où les solutions impliquant ps -ef
et grep
do (sur toute variante Unix prenant en charge les options POSIX pour ps
) et ne souffriront pas des faux positifs introduit par grepping pour une séquence de chiffres pouvant apparaître ailleurs.
Essayer
ps -p $$ -oargs=
ou
ps -p $$ -ocomm=
Si vous voulez juste vous assurer que l'utilisateur appelle un script avec bash:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
Tu peux essayer:
ps | grep `echo $$` | awk '{ print $4 }'
Ou:
echo $Shell
$Shell
n'a pas besoin de toujours montrer le shell actuel. Cela ne fait que refléter le shell par défaut à appeler.
Pour tester ce qui précède, dites que bash
est le shell par défaut, essayez echo $Shell
, puis dans le même terminal, entrez dans un autre shell (ksh par exemple) et essayez $Shell
, vous verrez le résultat est bash dans les deux cas.
Pour obtenir le nom du shell actuel, utilisez cat /proc/$$/cmdline
et le chemin d'accès à l'exécutable du shell par readlink /proc/$$/exe
ps est la méthode la plus fiable. L'environnement de Shell n'est pas garanti et, même s'il l'est, il peut être facilement falsifié.
J'ai un truc simple pour trouver le shell actuel. Il suffit de taper une chaîne aléatoire (qui n'est pas une commande). Il échouera et retournera une erreur "introuvable", mais en début de ligne, il indiquera quel shell il s'agit:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Cela donnera toujours le Shell utilisé - obtiendra le nom du fichier exécutable réel et non le nom du Shell (c'est-à-dire ksh93
au lieu de ksh
etc.). Pour /bin/sh
, le Shell utilisé: ie dash
ls -l /proc/$$/exe | sed 's%.*/%%'
Je sais qu'il y en a beaucoup qui disent que ls
la sortie devrait être traitée plus récemment, mais quelle est la probabilité que vous utilisiez un Shell nommé avec des caractères spéciaux ou placé dans un répertoire nommé avec des caractères spéciaux? Si tel est toujours le cas, voici d’autres exemples qui procèdent différemment.
J'ai essayé de nombreuses approches différentes et la meilleure pour moi est:
ps -p $$
Cela fonctionne également sous Cygwin et ne peut pas produire de faux positifs en tant que grep de PID. Avec un peu de nettoyage, il ne sort qu’un nom d’exécutable (sous Cygwin avec chemin):
ps -p $$ | tail -1 | awk '{print $NF}'
Vous pouvez créer une fonction pour ne pas avoir à la mémoriser:
# print currently active Shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... puis exécutez simplement Shell
.
Testé sous Debian et Cygwin.
Ma variante lors de l'impression du processus parent.
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
Pourquoi exécuter des applications inutiles, quand 'awk' peut le faire pour vous?
À condition que votre /bin/sh
prenne en charge le standard POSIX et que votre système ait la commande lsof
installée - une alternative possible à lsof
pourrait dans ce cas être pid2path
- vous pouvez également utiliser ( ou adapter) le script suivant qui imprime les chemins complets:
#!/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}'
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' #use the PID to see what the process is.
Aucune des réponses n'a fonctionné avec fish
Shell (il n'a pas de variables $$
ou $0
).
Cela fonctionne pour moi (testé sur sh
, bash
, fish
, ksh
, csh
, true
, tcsh
, et zsh
; openSUSE 13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
Cette commande génère une chaîne telle que bash
. J'utilise ici uniquement ps
, tail
et sed
(sans GNU extesions; essayez d'ajouter --posix
pour le vérifier). Ce sont tous des commandes POSIX standard. Je suis sûr que tail
peut être supprimé, mais mon sed
fu n'est pas assez puissant pour le faire.
Il me semble que cette solution n’est pas très portable car elle ne fonctionne pas sous OS X. :(
Il existe de nombreuses façons de découvrir le shell et sa version correspondante. En voici quelques-uns qui ont fonctionné pour moi.
Droit devant
approche Hackish
$> ******* (Tapez un ensemble de caractères aléatoires et dans la sortie, vous obtiendrez le nom du shell. Dans mon cas - bash: chapitre2-a-sample-isomorphic- app: commande non trouvée )
Ce n'est pas une solution très propre, mais fait ce que vous voulez.
Je me rends compte que la réponse est un peu tardive dans ce bon vieux 2015, mais ...
#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
Maintenant, vous pouvez utiliser $(getshell) --version.
Cela ne fonctionne, cependant, que sur les coquilles ressemblant à ksh.
Sur Mac OS X (et FreeBSD):
ps -p $$ -axco command | sed -n '$p'
Ma solution:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Cela devrait être portable sur différentes plates-formes et coques. Il utilise ps
comme d'autres solutions, mais il ne s'appuie pas sur sed
ou awk
et filtre les fichiers indésirables de la tuyauterie et ps
lui-même, de sorte que le shell doit toujours être le dernière entrée. De cette façon, nous n’avons pas besoin de recourir à des variables PID non portables ni de choisir les bonnes lignes et colonnes.
J'ai testé sur Debian et MacOS avec bash, zsh et fish (ce qui ne fonctionne pas avec la plupart de ces solutions sans changer l'expression spécifiquement pour fish, car elle utilise une variable PID différente).
Il n'est pas nécessaire d'insérer PID à partir de la sortie de "ps", car vous pouvez lire la ligne de commande correspondante pour tout PID de la structure de répertoire/proc:
echo $(cat /proc/$$/cmdline)
Cependant, cela pourrait ne pas être meilleur que simplement:
echo $0
À propos de l’exécution d’un shell différent de celui indiqué par le nom, l’idée est de demander une version de Shell au nom précédent:
<some_Shell> --version
sh semble échouer avec le code de sortie 2 alors que d'autres donnent quelque chose d'utile (mais je ne peux pas tout vérifier car je ne les ai pas):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Procédez comme suit pour savoir si votre shell utilise DASH/BASH.
1) ls –la/bin/sh, si le résultat est / bin/sh ->/bin/bash ==> Ensuite, votre shell utilise BASH.
si le résultat est / bin/sh ->/bin/dash ==> Votre shell utilise alors DASH.
Si vous souhaitez passer de BASH à DASH ou inversement, utilisez le code ci-dessous ln -s/bin/bash/bin/sh (changez Shell en BASH)
REMARQUE: Si la commande ci-dessus entraîne une erreur indiquant que/bin/sh existe déjà, supprimez le fichier/bin/sh et réessayez.
Si vous voulez juste vérifier que vous utilisez (une version particulière de) Bash, le meilleur moyen de le faire est d'utiliser la variable de tableau $BASH_VERSINFO
. En tant que variable de tableau (en lecture seule), il ne peut pas être défini dans l'environnement. Vous pouvez donc être sûr qu'elle provient (le cas échéant) du Shell en cours. Cependant, Bash ayant un comportement différent lorsqu'il est appelé sh
, vous devez également vérifier que la variable d'environnement $BASH
se termine par /bash
.
Dans un script que j'ai écrit qui utilise des noms de fonction avec -
(sans trait de soulignement) et dépend de tableaux associatifs (ajoutés dans Bash 4), j'ai le contrôle de cohérence suivant (avec un message d'erreur utile à l'utilisateur):
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
Dans le premier cas, vous pouvez omettre la vérification fonctionnelle quelque peu paranoïaque des fonctionnalités et supposer que les futures versions de bash seront compatibles.
Veuillez utiliser la commande ci-dessous:
# ps -p $$ | tail -1 | awk '{print $4}'