linux - resueltos - ¿Cómo puedo saber el nombre del archivo de script en un script de Bash?
shell script linux español (21)
¿Cómo puedo determinar el nombre del archivo de script Bash dentro del propio script?
Como si mi script runme.sh
en el archivo runme.sh
, entonces, ¿cómo lo haría para mostrar el mensaje "Está ejecutando runme.sh" sin codificarlo?
Con bash> = 3 los siguientes trabajos:
$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s
$ cat s
#!/bin/bash
printf ''$0 is: %s/n$BASH_SOURCE is: %s/n'' "$0" "$BASH_SOURCE"
Dado que algunos comentarios preguntaron sobre el nombre de archivo sin extensión, aquí hay un ejemplo de cómo lograrlo:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
¡Disfrutar!
En bash
puedes obtener el nombre del archivo de script usando $0
. Generalmente, $1
, $2
etc. son para acceder a los argumentos de la CLI. De manera similar, $0
es acceder al nombre que activa el script (nombre del archivo de script).
#!/bin/bash
echo "You are running $0"
...
...
Si invoca el script con la ruta como /path/to/script.sh
, $0
también le dará el nombre del archivo con la ruta. En ese caso, debe usar $(basename $0)
para obtener solo el nombre del archivo de script.
Estas respuestas son correctas para los casos que indican, pero aún existe un problema si ejecuta la secuencia de comandos desde otra secuencia de comandos usando la palabra clave ''fuente'' (para que se ejecute en el mismo shell). En este caso, obtienes los $ 0 del script de llamada. Y en este caso, no creo que sea posible obtener el nombre del script en sí.
Este es un caso de borde y no debe tomarse DEMASIADO en serio. Si ejecuta el script desde otro script directamente (sin ''fuente''), el uso de $ 0 funcionará.
He encontrado que esta línea siempre funciona, independientemente de si el archivo se está obteniendo o se ejecuta como un script.
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
Si desea seguir los enlaces simbólicos, use el readlink
de readlink
en la ruta que aparece arriba, recursivamente o no recursivamente.
El motivo por el que funciona una línea se explica por el uso de la variable de entorno BASH_SOURCE
y su FUNCNAME
asociado.
BASH_SOURCE
Una variable de matriz cuyos miembros son los nombres de archivo de origen donde se definen los nombres de función de shell correspondientes en la variable de matriz FUNCNAME. La función de shell $ {FUNCNAME [$ i]} se define en el archivo $ {BASH_SOURCE [$ i]} y se llama desde $ {BASH_SOURCE [$ i + 1]}.
Nombre de pila
Una variable de matriz que contiene los nombres de todas las funciones de shell actualmente en la pila de llamadas de ejecución. El elemento con índice 0 es el nombre de cualquier función de shell que se esté ejecutando actualmente. El elemento que está más abajo (el que tiene el índice más alto) es "principal". Esta variable existe solo cuando se está ejecutando una función de shell. Las asignaciones a FUNCNAME no tienen efecto y devuelven un estado de error. Si FUNCNAME no está configurado, pierde sus propiedades especiales, incluso si se reinicia posteriormente.
Esta variable se puede utilizar con BASH_LINENO y BASH_SOURCE. Cada elemento de FUNCNAME tiene elementos correspondientes en BASH_LINENO y BASH_SOURCE para describir la pila de llamadas. Por ejemplo, se llamó a $ {FUNCNAME [$ i]} desde el archivo $ {BASH_SOURCE [$ i + 1]} en el número de línea $ {BASH_LINENO [$ i]}. El integrante de la persona que llama muestra la pila de llamadas actual con esta información.
[Fuente: manual de Bash]
Información gracias a Bill Hernández. He añadido algunas preferencias que estoy adoptando.
#!/bin/bash
function Usage(){
echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
echo
echo "# arguments called with ----> ${@} "
echo "# /$1 -----------------------> $1 "
echo "# /$2 -----------------------> $2 "
echo "# path to me ---------------> ${0} " | sed "s/$USER//$USER/g"
echo "# parent path --------------> ${0%/*} " | sed "s/$USER//$USER/g"
echo "# my name ------------------> ${0##*/} "
echo
}
Aclamaciones
Para responder a Chris Conway , en Linux (al menos) harías esto:
echo $(basename $(readlink -nf $0))
readlink imprime el valor de un enlace simbólico. Si no es un enlace simbólico, imprime el nombre del archivo. -n le dice que no imprima una nueva línea. -f le dice que siga el enlace completamente (si un enlace simbólico fuera un enlace a otro enlace, también lo resolvería).
Puede usar $ 0 para determinar el nombre de su script (con la ruta completa): para obtener el nombre del script solo puede recortar esa variable con
basename $0
Re: la respuesta de Tanktalus (aceptada) arriba, una forma un poco más limpia es usar:
me=$(readlink --canonicalize --no-newline $0)
Si su script se ha obtenido de otro script de bash, puede usar:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Estoy de acuerdo en que sería confuso desreferenciar los enlaces simbólicos si su objetivo es proporcionar comentarios al usuario, pero hay ocasiones en las que necesita obtener el nombre canónico de un script u otro archivo, y esta es la mejor manera, imo.
Si el nombre del script tiene espacios en él, una forma más sólida es usar "$0"
o "$(basename "$0")"
o en MacOS: "$(basename /"$0/")"
. Esto evita que el nombre se dañe o se interprete de cualquier manera. En general, es una buena práctica siempre citar los nombres de las variables en el shell.
Si lo desea sin la ruta, usaría ${0##*/}
algo como esto?
export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh
#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size
echo "Would you like to empty Trash [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "''yes''"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "''no''"
fi
return $TRUE
}
#-----------------------------------------------------------------------
start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www open a homepage "
echo "htest trash empty trash "
return $TRUE
} #end Help
#-----------------------------------------------#
homepage=""
return $TRUE
} #end cpdebtemp
# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
val="*** Unknown ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
val=$1
fi
# use case statement to make decision for rental
case $val in
"trash") start_trash ;;
"help") start_help ;;
"www") firefox $homepage ;;
*) echo "Sorry, I can not get a $val for you!";;
esac
# Case stop
echo "estas corriendo $ 0"
si tu invocación de shell script como
/home/mike/runme.sh
$ 0 es el nombre completo
/home/mike/runme.sh
nombre base $ 0 obtendrá el nombre del archivo base
runme.sh
y necesitas poner este nombre básico en una variable como
filename=$(basename $0)
y agrega tu texto adicional
echo "You are running $filename"
a tus scripts les gusta
/home/mike/runme.sh
#!/bin/bash
filename=$(basename $0)
echo "You are running $filename"
$0
no responde la pregunta (como yo la entiendo). Una demostración:
$ cat script.sh #! /bin/sh echo `basename $0` $ ./script.sh script.sh $ ln script.sh linktoscript $ ./linktoscript linktoscript
¿Cómo se obtiene ./linktoscript
para imprimir script.sh
?
[EDITAR] Según @ephemient en los comentarios anteriores, aunque el enlace simbólico puede parecer ideado, es posible jugar con $0
para que no represente un recurso del sistema de archivos. El OP es un poco ambiguo sobre lo que quería.
$BASH_SOURCE
da la respuesta correcta al obtener el script.
Sin embargo, esto incluye la ruta para obtener solo el nombre de archivo de los scripts, usar:
$(basename $BASH_SOURCE)
# ------------- SCRIPT ------------- #
#!/bin/bash
echo
echo "# arguments called with ----> ${@} "
echo "# /$1 ----------------------> $1 "
echo "# /$2 ----------------------> $2 "
echo "# path to me ---------------> ${0} "
echo "# parent path --------------> ${0%/*} "
echo "# my name ------------------> ${0##*/} "
echo
exit
# ------------- CALLED ------------- #
# Notice on the next line, the first argument is called within double,
# and single quotes, since it contains two words
$ /misc/shell_scripts/check_root/show_parms.sh "''hello there''" "''william''"
# ------------- RESULTS ------------- #
# arguments called with ---> ''hello there'' ''william''
# $1 ----------------------> ''hello there''
# $2 ----------------------> ''william''
# path to me --------------> /misc/shell_scripts/check_root/show_parms.sh
# parent path -------------> /misc/shell_scripts/check_root
# my name -----------------> show_parms.sh
# ------------- END ------------- #
DIRECTORY=$(cd `dirname $0` && pwd)
Obtuve lo anterior de otra pregunta de desbordamiento de pila: ¿Puede un script de Bash indicar en qué directorio está almacenado? , pero creo que es útil para este tema también.
echo "$(basename "`test -L ${BASH_SOURCE[0]} /
&& readlink ${BASH_SOURCE[0]} /
|| echo ${BASH_SOURCE[0]}`")"
me=`basename "$0"`
Para leer a través de un enlace simbólico, que generalmente no es lo que quieres (normalmente no quieres confundir al usuario de esta manera), prueba:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
OMI, eso producirá resultados confusos. "Corrí foo.sh, pero está diciendo que estoy ejecutando bar.sh !? ¡Debe ser un error!" Además, uno de los propósitos de tener enlaces simbólicos con nombres diferentes es proporcionar una funcionalidad diferente basada en el nombre que se llama (piense gzip y gunzip en algunas plataformas).
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Esto resuelve los enlaces simbólicos (realpath lo hace), maneja los espacios (las comillas dobles lo hacen) y encontrará el nombre del script actual incluso cuando se obtenga (./myscript) o sea llamado por otros scripts ($ BASH_SOURCE lo maneja). Después de todo eso, es bueno guardar esto en una variable de entorno para reutilizarlo o para copiarlo fácilmente en otro lugar (esto =) ...