¿Cómo puedo determinar el shell actual en el que estoy trabajando?
¿ psSería suficiente la salida del comando?
¿Cómo se puede hacer esto en diferentes sabores de Unix?
¿Cómo puedo determinar el shell actual en el que estoy trabajando?
¿ psSería suficiente la salida del comando?
¿Cómo se puede hacer esto en diferentes sabores de Unix?
Respuestas:
Hay tres enfoques para encontrar el nombre del ejecutable del shell actual:
Tenga en cuenta que los tres enfoques pueden ser engañados si el ejecutable del shell es /bin/sh, pero en realidad es un cambio de nombre bash, por ejemplo (lo que sucede con frecuencia).
Por lo tanto, su segunda pregunta sobre si la pssalida funcionará se responde con " no siempre ".
echo $0 - imprimirá el nombre del programa ... que en el caso del shell es el shell real.
ps -ef | grep $$ | grep -v grep- esto buscará el ID del proceso actual en la lista de procesos en ejecución. Dado que el proceso actual es el shell, se incluirá.
Esto no es 100% confiable, ya que es posible que tenga otros procesos cuya pslista incluya el mismo número que el ID de proceso del shell, especialmente si ese ID es un número pequeño (por ejemplo, si el PID del shell es "5", puede encontrar procesos llamados "java5" o "perl5" en la misma grepsalida!). Este es el segundo problema con el enfoque "ps", además de no poder confiar en el nombre del shell.
echo $SHELL- La ruta al shell actual se almacena como la SHELLvariable para cualquier shell. La advertencia para esto 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 es una posibilidad, use el enfoque pso $0.
Sin embargo, si el ejecutable no coincide con su shell real (por ejemplo, en /bin/shrealidad es bash o ksh), necesita heurística. Aquí hay algunas variables ambientales específicas para varios shells:
$version está configurado en tcsh
$BASH se establece en bash
$shell (minúscula) se establece en el nombre real del shell en csh o tcsh
$ZSH_NAME está configurado en zsh
ksh tiene $PS3y $PS4establece, mientras que el shell Bourne normal ( sh) solo tiene $PS1y $PS2establece. Esto parece generalmente como el más difícil de distinguir - la única diferencia en todo el conjunto de variables de entorno entre shy kshhemos instalado en Solaris es Boxen $ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, $SECONDS, y $TMOUT.
echo ${.sh.version}devuelve "Mala sustitución". Vea mi solución arriba
ps -ef | grep …... Esto no es 100% fiable como ...” Usando una expresión regular simple a través de egrepo grep -efácilmente puede traer la fiabilidad hasta para-todo-intenciones-y-fines 100%: ps -ef | egrep "^\s*\d+\s+$$\s+". Se ^asegura de que estamos comenzando desde el principio de la línea, se \d+come el UID, $$coincide con el PID y el \s*y \s+representa y garantiza el espacio en blanco entre las otras partes.
ps -ef | awk '$2==pid' pid=$$
ps -p $$
debería funcionar en cualquier lugar donde las soluciones involucren ps -efy lo grephagan (en cualquier variante de Unix que admita las opciones POSIXps ) y no sufrirá los falsos positivos introducidos por grepping para una secuencia de dígitos que puede aparecer en otros lugares.
pscual puede que no se entienda, -ppor lo que es posible que deba usarla /bin/ps -p $$.
$$excepto los fishque tendrías que usar ps -p %self.
/bin/ps. pspodría instalarse fácilmente (en realidad es bastante normal hoy en día) /usr/bin. $(which ps) -p $$Es una mejor manera. Por supuesto, esto no funcionará en peces, y posiblemente en otras conchas. Creo que está (which ps) -p %selfen el pescado.
readlink /proc/$$/exe
shes emulado por bash, ps -p te da /usr/bin/bashincluso lo ejecutas comosh
Tratar
ps -p $$ -oargs=
o
ps -p $$ -ocomm=
ps -o fname --no-headers $$.
test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash. (La siguiente línea en mi script tiene el equivalente para csh.)
-qlugar de -p:SHELL=$(ps -ocomm= -q $$)
Si solo quiere asegurarse de que el usuario invoque un script con Bash:
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. Con esta línea, el script se ejecuta usando bash incluso si se comenzó a usar ksh o sh. Mi caso de uso no necesita argumentos de línea de comando, pero podrían agregarse después $0si es necesario.
Puedes probar:
ps | grep `echo $$` | awk '{ print $4 }'
O:
echo $SHELL
/pattern/ { action }lo hará?
$SHELLLa variable de entorno contiene un shell, que está configurado como predeterminado para un usuario actual. No refleja un shell, que se está ejecutando actualmente. También es mejor usar ps -p $$que grepping $$ debido a falsos positivos.
awk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELLNo siempre es necesario mostrar el shell actual. Solo refleja el shell predeterminado que se invocará.
Para probar lo anterior, digamos que bashes el shell predeterminado, intente echo $SHELL, y luego en el mismo terminal, ingrese a otro shell ( KornShell (ksh) por ejemplo) e intente $SHELL. Verá el resultado como bash en ambos casos.
Para obtener el nombre del shell actual, use cat /proc/$$/cmdline. Y la ruta al shell ejecutable por readlink /proc/$$/exe.
/proc.
ps es el método más confiable. No se garantiza que se establezca la variable de entorno SHELL e incluso si lo es, se puede suplantar fácilmente.
Tengo un simple truco 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á de qué shell se trata:
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
echo 'aaaa' > script; chmod +x script; ./scriptda./script.sh: 1: aaaa: not found
Lo siguiente siempre dará el shell real utilizado: obtiene el nombre del ejecutable real y no el nombre del shell (es decir, en ksh93lugar de ksh, etc.). Para /bin/sh, mostrará el shell real utilizado, es decir dash.
ls -l /proc/$$/exe | sed 's%.*/%%'
Sé que hay muchos que dicen que la lssalida nunca debe procesarse, pero ¿cuál es la probabilidad de que tenga un shell que está usando que se nombra con caracteres especiales o se coloca en un directorio con caracteres especiales? Si este sigue siendo el caso, hay muchos otros ejemplos de hacerlo de manera diferente.
Como señaló Toby Speight , esta sería una forma más adecuada y limpia de lograr lo mismo:
basename $(readlink /proc/$$/exe)
/proc. No todo el mundo es una caja de Linux.
basename $(readlink /proc/$$/exe)a ls+ sed+ echo.
ash -> /bin/busybox, esto dará / bin / busybox.
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 grepping PID. Con un poco de limpieza, genera solo un nombre ejecutable (en Cygwin con ruta):
ps -p $$ | tail -1 | awk '{print $NF}'
Puede crear una función para no tener que memorizarla:
# Print currently active shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
... y luego simplemente ejecuta shell.
Fue probado bajo Debian y Cygwin.
ps, taily gawk, cmd no se define $$como su PID, por lo que definitivamente no puede funcionar bajo el cmd simple.
ps -p$$ -o comm=? POSIX dice que especificar todos los encabezados vacíos suprime el encabezado por completo. Todavía estamos fallando (como todas las psrespuestas) cuando nos obtiene un script ejecutado directamente (por ejemplo #!/bin/sh).
Mi variante para imprimir el proceso padre:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
No ejecute aplicaciones innecesarias cuando AWK pueda hacerlo por usted.
awk, cuando ps -p "$$" -o 'comm='puede hacerlo por usted?
Hay muchas formas de averiguar el shell y su versión correspondiente. Aquí hay algunos que me funcionaron.
Sencillo
Enfoque hackish
$> ******* (Escriba un conjunto de caracteres aleatorios y en la salida obtendrá el nombre del shell. En mi caso -bash: chapter2-a-sample-isomorphic-app: comando no encontrado )
Siempre que /bin/shadmita el estándar POSIX y su sistema tenga lsofinstalado el comando, una posible alternativa a lo que lsofpodría ser en este caso pid2path, también puede usar (o adaptar) el siguiente script que imprime las 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}'
-iopción (-> ignorar entorno) enven la línea donde verifica si lsofestá disponible. falla con: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
Si solo desea verificar que está ejecutando (una versión particular de) Bash, la mejor manera de hacerlo es usar la $BASH_VERSINFOvariable de matriz. Como una variable de matriz (solo lectura) no se puede establecer en el entorno, por lo que puede estar seguro de que proviene (si es que lo hace) del shell actual.
Sin embargo, dado que Bash tiene un comportamiento diferente cuando se invoca como sh, también es necesario verificar que la $BASHvariable de entorno termina con /bash.
En un script que escribí que usa nombres de funciones con -(no subrayado), y depende de matrices asociativas (agregadas en Bash 4), tengo la siguiente comprobación de cordura (con un útil mensaje de error del usuario):
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
Podría omitir la comprobación funcional paranoica de las funciones en el primer caso, y simplemente asumir que las futuras versiones de Bash serían compatibles.
Ninguna de las respuestas funcionó con fishshell (no tiene las variables $$o $0).
Esto funciona para mí (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. Aquí solo estoy usando ps, taily sed(sin extensiones GNU; intente agregar --posixpara verificarlo). Todos son comandos POSIX estándar. Estoy seguro de que tailse puede eliminar, pero mi sedfu no es lo suficientemente fuerte como para hacer esto.
Me parece que esta solución no es muy portátil ya que no funciona en OS X. :(
sed: invalid option -- 'E'en bash 3.2.51 y tcsh 6.15.00
Mi solución:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
Esto debería ser portátil en diferentes plataformas y shells. Se utiliza pscomo otras soluciones, pero no se basa en sedo awkfiltra la basura de las tuberías y de pssí misma para que el shell siempre sea la última entrada. De esta manera, no necesitamos confiar en variables PID no portátiles o elegir las líneas y columnas correctas.
He probado en Debian y macOS con Bash, Z shell ( zsh) y fish (que no funciona con la mayoría de estas soluciones sin cambiar la expresión específicamente para fish, porque usa una variable PID diferente).
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$no es confiable. ps -ef | awk -v pid=$$ '$2==pid { print $8 }'es mejor, pero ¿por qué no solo usar ps -p $$?
En Mac OS X (y FreeBSD):
ps -p $$ -axco command | sed -n '$p'
zsh, y me dio -bash.
mutt...: -b
No es necesario agrupar el PID de la salida de "ps", ya que puede leer la línea de comando correspondiente para cualquier PID desde la estructura del 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 al que indica el nombre, una idea es solicitar la versión del shell utilizando el nombre que obtuvo anteriormente:
<some_shell> --version
sh parece fallar con el código de salida 2 mientras que otros dan algo útil (pero no puedo verificarlo todo porque no los tengo):
$ sh --version
sh: 0: Illegal option --
echo $?
2
Esta no es una solución muy limpia, pero hace lo que quieres.
# 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
Ahora puedes usar $(getshell) --version.
Sin embargo, esto funciona solo en shells similares a KornShell (ksh).
dash, yashetc. Normalmente, si está utilizando bash, zsh, ksh, lo que sea - no debe preocuparse por esas cosas.
kshel conjunto de características es principalmente un subconjunto de bashcaracterísticas (aunque no lo he comprobado a fondo).
Haga lo siguiente para saber si su shell está usando Dash / Bash.
ls –la /bin/sh:
si el resultado es /bin/sh -> /bin/bash==> Entonces su shell está usando 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 (cambiar shell a Bash)
Nota : Si el comando anterior da como resultado un error que dice, / bin / sh ya existe, elimine / bin / sh e intente nuevamente.
Utilice amablemente el siguiente comando:
ps -p $$ | tail -1 | awk '{print $4}'
echo $SHELLhace lo que estás tratando de hacer y hazlo bien. El segundo tampoco es bueno, porque $SHELLla variable de entorno contiene un shell predeterminado para un usuario actual, no un shell actualmente en ejecución. Si, por ejemplo, lo bashconfiguro como shell predeterminado, ejecutar zshy echo $SHELL, se imprimirá bash.
echo $SHELLpuede ser basura: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
Este funciona bien en Red Hat Linux (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}'
!Probablemente, probar las capacidades particulares (por ejemplo, ¿hace sustitución?) Es más portátil que encontrar el nombre del shell. La costumbre local puede hacer que ejecute algo llamado/bin/shque podría ser ash, dash, bash, etc.