¿Cómo puedo determinar el nombre del archivo de script Bash dentro del propio script?
Al igual que si mi script está en el archivo runme.sh
, ¿cómo lo haría para mostrar el mensaje "Estás ejecutando runme.sh" sin codificar eso?
¿Cómo puedo determinar el nombre del archivo de script Bash dentro del propio script?
Al igual que si mi script está en el archivo runme.sh
, ¿cómo lo haría para mostrar el mensaje "Estás ejecutando runme.sh" sin codificar eso?
Respuestas:
me=`basename "$0"`
Para leer un enlace simbólico 1 , que generalmente no es lo que desea (por lo general, no desea confundir al usuario de esta manera), intente:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
OMI, eso producirá resultados confusos. "Ejecuté 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 le llama (piense en gzip y gunzip en algunas plataformas).
1 Es decir, para resolver enlaces simbólicos de modo que cuando el usuario ejecuta, foo.sh
que en realidad es un enlace simbólico bar.sh
, desea utilizar el nombre resuelto en bar.sh
lugar de foo.sh
.
$0
en el primer ejemplo está sujeto a la división de palabras, 3. $0
se pasa a basename, readlink y echo en una posición que le permita ser tratado como un interruptor de línea de comando . Sugiero lugar me=$(basename -- "$0")
o mucho más eficiente a expensas de la legibilidad, me=${0##*/}
. Para enlaces simbólicos, me=$(basename -- "$(readlink -f -- "$0")")
suponiendo utilidades gnu, de lo contrario será un script muy largo que no escribiré aquí.
# ------------- 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
# ------------- LLAMADO ------------- ## ------------- LLAMADO ------------- #
# Aviso en la siguiente línea, el primer argumento se llama dentro del doble, # Aviso en la siguiente línea, el primer argumento se llama dentro del doble,
# y comillas simples, ya que contiene dos palabras# y comillas simples, ya que contiene dos palabras
$ /misc/shell_scripts/check_root/show_parms.sh "'hola allí'" "'william'"/ misc / shell_scripts / check_root / show_parms . sh "'hola' '" "' william '"
# ------------- RESULTADOS ------------- ## ------------- RESULTADOS ------------- #
# argumentos llamados con ---> 'hola' 'william'# argumentos llamados con ---> 'hola' 'william'
# $ 1 ----------------------> 'hola'# $ 1 ----------------------> 'hola'
# $ 2 ----------------------> 'william'# $ 2 ----------------------> 'william'
# ruta hacia mí --------------> /misc/shell_scripts/check_root/show_parms.sh# ruta hacia mí --------------> /misc/shell_scripts/check_root/show_parms.sh
# ruta principal -------------> / misc / shell_scripts / check_root# ruta principal -------------> / misc / shell_scripts / check_root
# mi nombre -----------------> show_parms.sh# mi nombre -----------------> show_parms.sh
# ------------- FIN ------------- ## ------------- FIN ------------- #
show_params
, es decir, el nombre sin ninguna extensión opcional?
${0##*/}
. Probado con GitBash.
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"
dirname $BASE_SOURCE
" para obtener el directorio que ubicaron los scripts.
$BASH_SOURCE
da la respuesta correcta al obtener el script.
Sin embargo, esto incluye la ruta, así que para obtener solo el nombre de archivo de los scripts, use:
$(basename $BASH_SOURCE)
. <filename> [arguments]
, $0
daría el nombre del llamador de shell. Bueno, al menos en OSX seguro.
Si el nombre del script tiene espacios en él, de una manera más sólida es utilizar "$0"
o "$(basename "$0")"
- o en MacOS: "$(basename \"$0\")"
. Esto evita que el nombre sea destrozado o interpretado de ninguna manera. En general, es una buena práctica siempre entre comillas dobles nombres de variables en el shell.
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 por completo (si un enlace simbólico fuera un enlace a otro enlace, también resolvería ese enlace).
He encontrado que esta línea siempre funciona, independientemente de si el archivo se obtiene o se ejecuta como un script.
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
Si desea seguir el uso de enlaces simbólicos readlink
en la ruta que obtiene arriba, recursivamente o no recursivamente.
La razón por la que funciona One-liner se explica por el uso de la BASH_SOURCE
variable de entorno y su asociado FUNCNAME
.
BASH_SOURCE
Una variable de matriz cuyos miembros son los nombres de los archivos de origen donde se definen los nombres de funciones 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]}.
FUNCNAME
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 más inferior (el que tiene el índice más alto) es "principal". Esta variable existe solo cuando se ejecuta 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 restablece posteriormente.
Esta variable se puede usar 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, $ {FUNCNAME [$ i]} se llamó desde el archivo $ {BASH_SOURCE [$ i + 1]} en el número de línea $ {BASH_LINENO [$ i]}. La persona que llama muestra la pila de llamadas actual con esta información.
[Fuente: manual de Bash]
a
(se supone que a
el contenido es echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) de una sesión interactiva, entonces le dará a
la ruta. Pero si escribe un script b
con source a
él y lo ejecuta ./b
, devolverá b
la ruta.
Estas respuestas son correctas para los casos que indican, pero aún existe un problema si ejecuta el script desde otro script utilizando la palabra clave 'source' (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 marginal y no debe tomarse DEMASIADO en serio. Si ejecuta el script desde otro script directamente (sin 'fuente'), usar $ 0 funcionará.
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!
Re: Respuesta de Tanktalus (aceptada) arriba, una forma un poco más limpia es usar:
me=$(readlink --canonicalize --no-newline $0)
Si su script proviene de otro script 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, en mi opinión.
source
nombres de script d.
si su invocar shell script como
/home/mike/runme.sh
$ 0 es el nombre completo
/home/mike/runme.sh
basename $ 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"
así que a tus guiones les gusta
/home/mike/runme.sh
#!/bin/bash
filename=$(basename $0)
echo "You are running $filename"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Esto resuelve enlaces simbólicos (realpath hace eso), maneja espacios (las comillas dobles hacen esto) y encontrará el nombre del script actual incluso cuando se obtiene (. ./Myscript) o lo llaman otros scripts ($ BASH_SOURCE maneja eso). Después de todo eso, es bueno guardar esto en una variable de entorno para reutilizarlo o copiarlo fácilmente en otro lugar (esto =) ...
realpath
no es un comando BASH incorporado. Es un ejecutable independiente que solo está disponible en ciertas distribuciones
En bash
puede obtener el nombre del archivo de script utilizando $0
. Generalmente $1
, $2
etc. son para acceder a los argumentos de la CLI. Del mismo modo $0
es acceder al nombre que desencadena el script (nombre del archivo de script).
#!/bin/bash
echo "You are running $0"
...
...
Si invoca el script con una ruta como, /path/to/script.sh
entonces $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.
$0
no responde la pregunta (según tengo entendido). Una demostración:
$ cat script.sh #! / bin / sh echo `basename $ 0` $ ./script.sh script.sh $ ln script.sh linktoscript $ ./linktoscript linktoscript
¿Cómo se ./linktoscript
imprime script.sh
?
[EDITAR] Según @ephemient en los comentarios anteriores, aunque el enlace simbólico puede parecer artificial, es posible jugar con él de $0
tal manera que no represente un recurso del sistema de archivos. El OP es un poco ambiguo sobre lo que quería.
Información gracias a Bill Hernández. Agregué 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
}
Salud
Corto, claro y simple, en my_script.sh
#!/bin/bash
running_file_name=$(basename "$0")
echo "You are running '$running_file_name' file."
Fuera puesto:
./my_script.sh
You are running 'my_script.sh' file.
DIRECTORY=$(cd `dirname $0` && pwd)
Obtuve lo anterior de otra pregunta de Stack Overflow, ¿Puede un script Bash decir en qué directorio está almacenado? , pero creo que también es útil para este tema.
Esto es lo que se me ocurrió, inspirado en la respuesta de Dimitre Radoulov (que, por cierto, he votado) .
script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"
echo "Called $script with $# argument(s)"
independientemente de la forma en que llame a su script
. path/to/script.sh
o
./path/to/script.sh
¿Algo así?
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