bash - script - ¿Cómo determinar el shell actual en el que estoy trabajando?
scripts bash ejemplos (23)
En Mac OS X (y FreeBSD):
ps -p $$ -axco command | sed -n ''$p''
¿Cómo puedo determinar el shell actual en el que estoy trabajando?
¿Sería suficiente la salida del comando ps
solo?
¿Cómo se puede hacer esto en diferentes sabores de UNIX?
Esta no es una solución muy limpia, pero hace lo que usted quiere.
Me doy cuenta de que la respuesta es un poco tarde en este buen 2015, pero ...
#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
Ahora puedes usar $(getshell) --version.
Esto funciona, sin embargo, solo en shells tipo ksh.
Este funciona bien en RHEL, MacOS, BSD y algunos AIX.
ps -T $$ | awk ''NR==2{print $NF}''
alternativamente, el siguiente también debería funcionar si pstree está disponible,
pstree | egrep $$ | awk ''NR==2{print $NF}''
Esto le dará siempre el shell real utilizado: obtiene el nombre del ejecutable real y no el nombre del shell (es decir, ksh93
lugar de ksh
etc.) Para /bin/sh
mostrará el shell real utilizado: es decir, dash
ls -l /proc/$$/exe | sed ''s%.*/%%''
Sé que aquí hay muchos que dicen que la salida de ls
debería ser procesada más recientemente, pero ¿cuál es la probabilidad de que tenga un shell que esté usando con nombres de caracteres especiales o que se coloque en un directorio con caracteres especiales? Si este es el caso, aquí hay muchos otros ejemplos que lo hacen de manera diferente.
Grepping PID de la salida de "ps" no es necesario porque puede leer la línea de comando respectiva para cualquier PID desde la estructura de directorio / proc:
echo $(cat /proc/$$/cmdline)
Sin embargo, eso podría no ser mejor que simplemente:
echo $0
Acerca de ejecutar un shell realmente diferente de lo que el nombre indica, una idea es solicitar una versión del shell con el nombre que recibió anteriormente:
<some_shell> --version
Parece que sh falla con el código de salida 2 mientras que otros dan algo útil (pero no puedo verificar todo porque no los tengo):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Haga lo siguiente para saber si su Shell está usando DASH / BASH.
1) ls –la / bin / sh , si el resultado es / bin / sh -> / bin / bash ==> Entonces su shell está utilizando BASH.
si el resultado es / bin / sh -> / bin / dash ==> Entonces su shell está usando DASH.
Si desea cambiar de BASH a DASH o viceversa, use el siguiente código ln -s / bin / bash / bin / sh (cambie de shell a BASH)
NOTA: Si el comando anterior produce un mensaje de error, / bin / sh ya existe, elimine / bin / sh e intente nuevamente.
Hay muchas maneras de descubrir el shell y su versión correspondiente. Aquí hay algunos que trabajaron para mí.
Hacia adelante
- $> echo $ 0 (Te da el nombre del programa. En mi caso, la salida fue -bash )
- $> $ SHELL (Esto lo lleva al shell y en el indicador del sistema obtiene el nombre y la versión del shell. En mi caso bash3.2 $ )
- $> echo $ SHELL (Esto le dará una ruta ejecutable. En mi caso / bin / bash )
- $> $ SHELL --version (Esto le dará información completa sobre el software de shell con el tipo de licencia)
Enfoque de hackers
$> ******* (Escriba un conjunto de caracteres aleatorios y en la salida obtendrá el nombre de shell. En mi caso -bash: chapter2-a-sample-isomorphic-app: comando no encontrado )
He intentado muchos enfoques diferentes y el mejor para mí es:
ps -p $$
También funciona bajo Cygwin y no puede producir falsos positivos como PID grepping. Con algo de limpieza, solo genera un nombre ejecutable (bajo Cygwin con ruta):
ps -p $$ | tail -1 | awk ''{print $NF}''
Puedes crear una función para no tener que memorizarla:
# print currently active shell
shell () {
ps -p $$ | tail -1 | awk ''{print $NF}''
}
... y luego solo ejecuta shell
.
Probado bajo Debian y Cygwin.
Mi solución:
ps -o command | grep -v -e "/<ps/>" -e grep -e tail | tail -1
Esto debería ser portátil a través de diferentes plataformas y shells. Utiliza ps
como otras soluciones, pero no se basa en sed
o awk
y filtra la basura de las tuberías y ps
sí, por lo que la shell debe ser siempre la última entrada. De esta manera, no necesitamos depender de variables PID no portátiles o seleccionar las líneas y columnas correctas.
He probado en Debian y MacOS con bash, zsh y fish (que no funciona con la mayoría de estas soluciones sin cambiar la expresión específicamente para fish, porque utiliza una variable PID diferente).
Mi variante en la impresión del proceso padre.
ps -p $$ | awk ''$1 == PP {print $4}'' PP=$$
¿Por qué ejecutar aplicaciones innecesarias, cuando ''awk'' puede hacerlo por usted?
Ninguna de las respuestas funcionó con cáscara de fish
(no tiene variables $$
o $0
).
Esto me funciona (probado en sh
, bash
, fish
, ksh
, csh
, true
, tcsh
y zsh
; openSUSE 13.2):
ps | tail -n 4 | sed -E ''2,$d;s/.* (.*)//1/''
Este comando genera una cadena como bash
. Estoy usando aquí solo ps
, tail
y sed
(sin versiones GNU; intente agregar --posix
para verificarlo). Todos ellos son comandos POSIX estándar. Estoy seguro de que se puede quitar la tail
, pero mi sed
fu no es lo suficientemente fuerte para hacer esto.
Me parece que esta solución no es muy portátil ya que no funciona en OS X. :(
Puedes probar:
ps | grep `echo $$` | awk ''{ print $4 }''
O:
echo $SHELL
Si solo desea comprobar que está ejecutando (una versión particular de) Bash, la mejor manera de hacerlo es usar la variable de matriz $BASH_VERSINFO
. Como una variable de matriz (solo lectura) no se puede establecer en el entorno, por lo que puede estar seguro de que viene (si es que lo hace) del shell actual. Sin embargo, dado que Bash tiene un comportamiento diferente cuando se invoca como sh
, también debe verificar que la variable de entorno $BASH
termina con /bash
.
En una secuencia de comandos que escribí que usa nombres de funciones con -
(no subrayado) y depende de matrices asociativas (agregadas en Bash 4), tengo la siguiente verificación de cordura (con un mensaje de error de usuario útil):
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
En el primer caso, podría omitir la comprobación funcional algo paranoica para las funciones, y suponer que las futuras versiones de bash serían compatibles.
Si solo quiere asegurarse de que el usuario está invocando el script con bash:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
Siempre que su /bin/sh
compatible con el estándar POSIX y su sistema tenga instalado el comando lsof
en este caso, una posible alternativa a lsof
podría ser pid2path
; también puede usar (o adaptar) el siguiente script que imprime rutas completas:
#!/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}''
Tengo un truco simple para encontrar el shell actual. Simplemente escriba una cadena aleatoria (que no es un comando). Fallará y devolverá un error "no encontrado", pero al comienzo de la línea dirá qué shell es:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
Tratar
ps -p $$ -oargs=
o
ps -p $$ -ocomm=
Utilice amablemente el siguiente comando:
# ps -p $$ | tail -1 | awk ''{print $4}''
ps es el método más confiable. El envar SHELL no está garantizado para ser configurado e incluso si lo está, puede ser fácilmente falsificado
$SHELL
no necesita mostrar siempre el shell actual. Solo refleja el shell por defecto a invocar.
Para probar lo anterior, Say bash
es el shell predeterminado, intente echo $SHELL
, luego en el mismo terminal, ingrese en otro shell (ksh por ejemplo) y pruebe $SHELL
, verá el resultado como bash en ambos casos.
Para obtener el nombre del shell actual, use cat /proc/$$/cmdline
y la ruta al ejecutable del shell mediante readlink /proc/$$/exe
ps -p $$
Debería funcionar en cualquier lugar que las soluciones que involucran ps -ef
y grep
do (en cualquier variante de Unix que admita las opciones POSIX para ps
) y no sufran los falsos positivos introducidos por grepping para una secuencia de dígitos que pueden aparecer en otros lugares.
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk ''{print $8}'' #use the PID to see what the process is.
Hay 3 enfoques para encontrar el nombre del ejecutable del shell actual:
Tenga en cuenta que los 3 enfoques pueden ser engañados si el ejecutable del shell es
/bin/sh
pero en realidad es unbash
renombrado, por ejemplo (lo que sucede con frecuencia).Por lo tanto, la segunda pregunta sobre si la salida de
ps
será suficiente se responde con " no siempre ".echo $0
- imprimirá el nombre del programa ... que en el caso de shell es el shell realps -ef | grep $$ | grep -v grep
ps -ef | grep $$ | grep -v grep
: buscará el ID del proceso actual en la lista de procesos en ejecución. Dado que el proceso actual es shell, se incluirá.Esto no es 100% confiable, ya que podría tener OTROS procesos cuya lista de
ps
incluye el mismo número que el ID de proceso de shell, especialmente si esa ID es un pequeño # (por ejemplo, si el PID de shell es "5", puede encontrar procesos llamados "java5 "o" perl5 "en la misma salida degrep
!). Este es el segundo problema con el enfoque "ps", además de no poder confiar en el nombre de shell.echo $SHELL
: la ruta al shell actual se almacena como la variableSHELL
para cualquier shell. La advertencia para este caso es que si inicia un shell explícitamente como un subproceso (por ejemplo, no es su shell de inicio de sesión), obtendrá el valor de su shell de inicio de sesión. Si eso es una posibilidad, use el enfoqueps
o$0
.
Sin embargo, si el ejecutable no coincide con su shell real (por ejemplo,
/bin/sh
es en realidad bash o ksh), necesita heurísticas. Aquí hay algunas variables ambientales específicas para varias conchas:$version
está establecida en tcsh$BASH
se establece en bash$shell
(en minúsculas) se establece en el nombre de shell real en csh o tcsh$ZSH_NAME
se establece en zshksh tiene un conjunto de
$PS3
y$PS4
, mientras que el shell Bourne normal (sh
) solo tiene un conjunto de$PS1
y$PS2
. Esto generalmente parece ser el más difícil de distinguir: la ÚNICA diferencia en el conjunto completo de variables ambientales entresh
yksh
que hemos instalado en Solaris boxen es$ERRNO
,$FCEDIT
,$LINENO
,$PPID
,$PS3
,$PS4
,$RANDOM
,$SECONDS
,$TMOUT
.