¿Cómo obtengo la ruta del directorio en el que se encuentra un script Bash , dentro de ese script?
Quiero usar un script Bash como lanzador para otra aplicación. Quiero cambiar el directorio de trabajo al que está ubicado el script Bash, para poder operar en los archivos de ese directorio, así:
$ ./application

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)"- y eliminarlo sin una sustitución de comando -DIR="${DIR%x}".mkdir $'\n'.dirnamey que el directorio podría comenzar con un-(por ejemplo--help).DIR=$(reldir=$(dirname -- "$0"; echo x); reldir=${reldir%?x}; cd -- "$reldir" && pwd && echo x); DIR=${DIR%?x}. Tal vez esto es exagerado?Respuestas:
es una línea útil que le dará el nombre completo del directorio de la secuencia de comandos sin importar de dónde se llame.
Funcionará siempre que el último componente de la ruta utilizada para encontrar el script no sea un enlace simbólico (los enlaces de directorio están bien). Si también desea resolver cualquier enlace al script en sí, necesita una solución de varias líneas:
Este último funciona con cualquier combinación de alias,
source,bash -c, enlaces simbólicos, etc.Cuidado: si va
cda un directorio diferente antes de ejecutar este fragmento, ¡el resultado puede ser incorrecto!Además, tenga cuidado con las
$CDPATHtrampas y los efectos secundarios de salida de stderr si el usuario ha anulado de manera inteligente el cd para redirigir la salida a stderr en su lugar (incluidas las secuencias de escape, como cuando se llamaupdate_terminal_cwd >&2en Mac). Agregar>/dev/null 2>&1al final de sucdcomando se encargará de ambas posibilidades.Para entender cómo funciona, intente ejecutar esta forma más detallada:
E imprimirá algo como:
fuente
source <script>ybash <script>:DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)".cdimprime algo en STDOUT! Por ejemplo, si su$CDPATHcuenta.. Para cubrir este caso, useDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"dirname $(readlink -f $0)es el comando correcto Ver gist.github.com/tvlooy/cbfbdb111a4ebad8b93e para un caso de pruebadirname "$(readlink -f "$0")"no agrega complejidad y es una medida justa más robusta para la mínima cantidad de problemas.readlink -f $0dareadlink: illegal option -- f.Uso
dirname "$0":usar
pwdsolo no funcionará si no está ejecutando el script desde el directorio en el que está contenido.fuente
type -psi el script es ejecutable. Esto también puede abrir un agujero sutil si el script se ejecuta usandobash test2.shy hay otro script con el mismo nombre ejecutable en otro lugar.bashy la línea hash-bang menciona explícitamente/bin/bash, diría que es bastante seguro depender de los bashismos.dirname $0es que si el directorio es el directorio actual, obtendrá.. Eso está bien a menos que vayas a cambiar los directorios en el script y esperes usar la ruta que obtuvistedirname $0como si fuera absoluta. Para obtener la ruta absoluta:pushd `dirname $0` > /dev/null,SCRIPTPATH=`pwd`,popd > /dev/null: pastie.org/1489386 (Pero sin duda hay una mejor manera de ampliar ese camino?)dirname $0haya un problema si lo asigna a una variable y luego lo usa para iniciar un script como$dir/script.sh; Me imagino que este es el caso de uso para este tipo de cosas el 90% del tiempo../script.shfuncionaría bienEl
dirnamecomando es el más básico, simplemente analiza la ruta hasta el nombre de archivo fuera de la$0variable (nombre del script):Pero, como señaló Matt B , el camino devuelto es diferente dependiendo de cómo se llame el script.
pwdno hace el trabajo porque eso solo le dice cuál es el directorio actual, no en qué directorio reside el script. Además, si se ejecuta un enlace simbólico a un script, obtendrá una ruta (probablemente relativa) a donde reside el enlace, no el script real.Algunos otros han mencionado el
readlinkcomando, pero en su forma más simple, puede usar:readlinkresolverá la ruta del script a una ruta absoluta desde la raíz del sistema de archivos. Por lo tanto, cualquier ruta que contenga puntos simples o dobles, tildes y / o enlaces simbólicos se resolverá en una ruta completa.Aquí hay un script que demuestra cada uno de estos
whatdir.sh:Ejecutando este script en mi directorio de inicio, usando una ruta relativa:
De nuevo, pero usando la ruta completa al script:
Ahora cambiando directorios:
Y finalmente usando un enlace simbólico para ejecutar el script:
fuente
readlinkno estará disponible en alguna plataforma en la instalación predeterminada. Intenta evitar usarlo si puedesexport SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"-fno se reconoce como una opción parareadlink. Usar en sustat -flugar hace el trabajo. Graciasgreadlink, que es básicamente lareadlinkque todos conocemos. Aquí hay una versión independiente de la plataforma:dir=`greadlink -f ${BASH_SOURCE[0]} || readlink -f ${BASH_SOURCE[0]}`greadlinkse puede instalar fácilmente a través de homebrew:brew install coreutilsFunciona para todas las versiones, incluidas
source".operador aka (punto).$0se modifica de la persona que llama."./script""/full/path/to/script""/some/path/../../another/path/script""./some/folder/script"Alternativamente, si el script bash en sí es un enlace simbólico relativo , desea seguirlo y devolver la ruta completa del script vinculado:
SCRIPT_PATHse da en ruta completa, no importa cómo se llame.Solo asegúrate de localizar esto al comienzo del script.
Este comentario y código Copyleft, licencia seleccionable bajo la GPL2.0 o posterior o CC-SA 3.0 (CreativeCommons Share Alike) o posterior. (c) 2008. Todos los derechos reservados. Sin garantía de ningún tipo. Usted ha sido advertido.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656
fuente
readlink -f $(dirname "${VIRTUAL_ENV}");dirname "${SCRIPT_PATH}"&& pwd)? Pero de todos modos gran guión!cdsalga de su directorio actual con la esperanza decdvolver a aparecer más tarde: la secuencia de comandos puede no tener permiso para volver a cambiar el directorio actual al que se invocó. (Lo mismo ocurre con pushd / popd)readlink -fes específico de GNU. BSDreadlinkno tiene esa opción.([ ... ])es menos eficiente que[ ... ], y no se aprovecha el aislamiento ofrecido a cambio de ese rendimiento alcanzado aquí.Respuesta corta:
o ( preferiblemente ):
fuente
sourceycd $(dirname $0)es fácil de recordar.${BASH_SOURCE[0]}lugar de$0trabajar consource my/script.sh${BASH_SOURCE[0]}no es satisfactorio en absoluto${BASH_SOURCE:-0}es mucho mejor.Puedes usar
$BASH_SOURCE:Tenga en cuenta que debe usar
#!/bin/bashy no,#!/bin/shya que es una extensión Bash.fuente
./foo/script, entonces lo$(dirname $BASH_SOURCE)es./foo.realpathcomando para obtener la ruta completa de ./foo/script. Asídirname $(realpath ./foo/script)dará el camino del guión.Esto debería hacerlo:
Esto funciona con enlaces simbólicos y espacios en la ruta.
Vea las páginas de manual para
dirnameyreadlink.De la pista de comentarios parece que no funciona con Mac OS. No tengo idea de por qué es eso. ¿Alguna sugerencia?
fuente
./script.shmuestra en.lugar de la ruta completa del directoriostatlugar. Pero aún así, muestra.si estás en 'este' directorio.coreutilsdesde Homebrew y usarlogreadlinkpara obtener la-fopción en MacOS porque es * BSD debajo de las cubiertas y no Linux.DIR="$(dirname "$(readlink -f "$0")")"pwdse puede usar para encontrar el directorio de trabajo actual ydirnamepara encontrar el directorio de un archivo en particular (el comando que se ejecutó es$0, pordirname $0lo tanto, debería darle el directorio del script actual).Sin embargo,
dirnameproporciona con precisión la parte del directorio del nombre de archivo, que probablemente será relativa al directorio de trabajo actual. Si su script necesita cambiar de directorio por alguna razón, entonces la salida de no tienedirnamesentido.Sugiero lo siguiente:
De esta manera, obtienes un directorio absoluto, más que relativo.
Dado que el script se ejecutará en una instancia de bash separada, no es necesario restaurar el directorio de trabajo después, pero si desea volver a cambiar su script por alguna razón, puede asignar fácilmente el valor de
pwduna variable antes de cambiar directorio, para uso futuro.Aunque solo
resuelve el escenario específico en la pregunta, creo que tener el camino absoluto a más más generalmente útil.
fuente
dirname $0&& pwd)Estoy cansado de ir a esta página una y otra vez para copiar y pegar la línea en la respuesta aceptada. El problema con eso es que no es fácil de entender y recordar.
Aquí hay un script fácil de recordar:
fuente
DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")realpathde resolver "manualmente" con un bucle dereadlink? Incluso lareadlinkpágina del manual diceNote realpath(1) is the preferred command to use for canonicalization functionality.realpathantesdirname, no después? Si el archivo de script en sí es un enlace simbólico ... Daría algo asíDIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")". En realidad muy cerca de la respuesta propuesta por Simon.No creo que esto sea tan fácil como lo han hecho otros.
pwdno funciona, ya que el directorio actual no es necesariamente el directorio con el script.$0no siempre tiene la información tampoco. Considere las siguientes tres formas de invocar un script:En la primera y tercera forma
$0no tiene la información de ruta completa. En el segundo y tercero,pwdno funciona. La única forma de obtener el directorio de la tercera forma sería ejecutar la ruta y encontrar el archivo con la coincidencia correcta. Básicamente, el código tendría que rehacer lo que hace el sistema operativo.Una forma de hacer lo que está pidiendo sería simplemente codificar los datos en el
/usr/sharedirectorio y hacer referencia a ellos por su ruta completa. Los datos no deben estar en el/usr/bindirectorio de todos modos, por lo que probablemente sea lo que hay que hacer.fuente
fuente
$0nipwdse garantiza que tengan la información correcta, dependiendo de cómo se invoque el script.fuente
$BASH_SOURCEmás$0, porque es explícito incluso para lectores que no están bien versados en bash.$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")Esto obtiene el directorio de trabajo actual en Mac OS X 10.6.6:
fuente
Esto es específico de Linux, pero podría usar:
fuente
/proc/fd/$$/255parece apuntar a tty, no a un directorio. Por ejemplo, en mi shell de inicio de sesión actual, todos los descriptores de archivo 0, 1, 2 y 255 hacen referencia/dev/pts/4. En cualquier caso, el manual de bash no menciona fd 255, por lo que probablemente no sea prudente depender de este comportamiento. \realpath ${BASH_SOURCE[0]};, parece ser el mejor camino a seguir.Aquí hay un one-liner compatible con POSIX:
fuente
cdse configura para imprimir el nuevo nombre de ruta.Intenté todo esto y ninguno funcionó. Uno estaba muy cerca pero tenía un pequeño error que lo rompió gravemente; se olvidaron de envolver el camino entre comillas.
Además, muchas personas suponen que está ejecutando el script desde un shell, por lo que se olvidan que cuando abre un nuevo script, el valor predeterminado es su hogar.
Pruebe este directorio para ver el tamaño:
Esto lo hace bien independientemente de cómo o dónde lo ejecute:
Entonces, para que sea realmente útil, aquí le mostramos cómo cambiar al directorio del script en ejecución:
fuente
ln -s ../bin64/foo /usr/bin/foo).Aquí está la forma simple y correcta:
Explicación:
${BASH_SOURCE[0]}- la ruta completa al guión. El valor de esto será correcto incluso cuando se está obteniendo el script, por ejemplo,source <(echo 'echo $0')imprime bash , mientras que si lo reemplaza${BASH_SOURCE[0]}imprimirá la ruta completa del script. (Por supuesto, esto supone que estás bien tomando una dependencia de Bash).readlink -f- Resuelve recursivamente cualquier enlace simbólico en la ruta especificada. Esta es una extensión GNU y no está disponible en (por ejemplo) sistemas BSD. Si está ejecutando una Mac, puede usar Homebrew para instalar GNUcoreutilsy suplantar esto congreadlink -f.Y, por supuesto,
dirnameobtiene el directorio principal de la ruta.fuente
greadlink -fdesafortunadamente no funciona de manera efectiva cuando sesourceejecuta el script en Mac :(La forma más corta y elegante de hacer esto es:
Esto funcionaría en todas las plataformas y es súper limpio.
Se pueden encontrar más detalles en " ¿En qué directorio está ese script bash? ".
fuente
Yo usaría algo como esto:
fuente
shtambién! Problema condirname "$0"soluciones simples : si el script está en$PATHy se invoca sin ruta, dará un resultado incorrecto.PATH,$0contendrá el nombre de archivo absoluto. Si la secuencia de comandos se invoca con un nombre de archivo relativo o absoluto que contiene un/,$0lo contendrá.Esta es una ligera revisión de la solución e-satis y 3bcdnlklvc04a señalaron en su respuesta :
Esto aún debería funcionar en todos los casos enumerados.
Esto evitará
popddespués de unpushderror, gracias a konsolebox.fuente
SCRIPT_DIR=''; pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && { SCRIPT_DIR=$PWD; popd > /dev/null; }popden casos (incluso cuando es raro) dondepushdfalla. Y en caso de quepushdfalle, ¿cuál crees que debería ser el valorSCRIPT_DIR? La acción puede variar dependiendo de lo que pueda parecer lógico o de lo que un usuario podría preferir, pero ciertamente, hacerlopopdes incorrecto.pushdpopdpeligros podrían evitarse simplemente dejándolos caer y usandocd+pwdencerrado en una sustitución de comando.SCRIPT_DIR=$(...)Para sistemas que tienen GNU coreutils
readlink(por ejemplo, linux):No hay necesidad de usar
BASH_SOURCEcuando$0contiene el nombre de archivo del script.fuente
dirnamellamada. Necesario si la ruta del directorio contiene espacios.fuente
$0no funcionará para un script de origen$_Vale la pena mencionar como una alternativa a$0. Si está ejecutando un script desde Bash, la respuesta aceptada se puede acortar a:Tenga en cuenta que esta debe ser la primera declaración en su secuencia de comandos.
fuente
sourceo.el guión. En esas situaciones,$_contendría el último parámetro del último comando que ejecutó antes de..$BASH_SOURCEFunciona todo el tiempo.He comparado muchas de las respuestas dadas y encuentro algunas soluciones más compactas. Estos parecen manejar todos los casos de borde loco que surgen de su combinación favorita de:
script,bash script,bash -c script,source script, o. scriptSi está ejecutando desde Linux, parece que usar el
procidentificador es la mejor solución para localizar la fuente totalmente resuelta del script que se está ejecutando actualmente (en una sesión interactiva, el enlace apunta al respectivo/dev/pts/X):Esto tiene un poco de fealdad, pero la solución es compacta y fácil de entender. No estamos usando bash primitivos solamente, pero estoy de acuerdo con eso porque
readlinksimplifica la tarea considerablemente. Laecho Xsuma unaXal final de la cadena variable de modo que cualquier espacio en blanco final en el nombre del archivo no ser comido, y la sustitución de parámetros${VAR%X}al final de la línea se deshace de laX. Debido a quereadlinkagrega una nueva línea propia (que normalmente se comería en la sustitución de comandos si no fuera por nuestro truco anterior), también tenemos que deshacernos de eso. Esto se logra más fácilmente usando el$''esquema de citas, que nos permite usar secuencias de escape como\npara representar nuevas líneas (esta es también la forma en que puede crear fácilmente directorios y archivos con nombres desviados)Lo anterior debe cubrir sus necesidades para localizar el script que se está ejecutando actualmente en Linux, pero si no tiene el
procsistema de archivos a su disposición, o si está tratando de localizar la ruta completamente resuelta de algún otro archivo, entonces tal vez encuentra útil el siguiente código. Es solo una ligera modificación de la línea anterior. Si está jugando con directorios / nombres de archivo extraños, verifica la salida con amboslsyreadlinkes informativo, ya quelsgenerará rutas "simplificadas", sustituyendo?cosas como líneas nuevas.fuente
/dev/pts/30con bash en Ubuntu 14.10 Desktop.echo $resolved, me guardé comod,chmod +x d,./d.#!/bin/bashIntenta usar:
fuente
$0para${BASH_SOURCE[0]}que funcione en cualquier lugar, incluso en una función.dirnameporque la última parte de$0puede ser un enlace simbólico que apunta a un archivo que no está en el mismo directorio que el enlace simbólico en sí. La solución descrita en esta respuesta solo obtiene la ruta del directorio donde se almacenó el enlace simbólico, no el directorio del destino. Además, a esta solución le faltan citas. No funcionará si la ruta contiene caracteres especiales.dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"Pruebe la siguiente solución de compatibilidad cruzada:
ya que los comandos como
realpathoreadlinkpodrían no estar disponibles (dependiendo del sistema operativo).Nota: en Bash, se recomienda usar en
${BASH_SOURCE[0]}lugar de$0, de lo contrario, la ruta puede romperse al obtener el archivo (source/.).Alternativamente, puede probar la siguiente función en bash:
Esta función toma 1 argumento. Si el argumento ya tiene una ruta absoluta, imprímala como está, de lo contrario imprima
$PWDvariable + argumento del nombre del archivo (sin./prefijo)Relacionado:
fuente
realpathfunción @Chris toma 1 argumento. Si el argumento ya tiene una ruta absoluta, imprímala como está, de lo contrario imprima$PWD+ nombre de archivo (sin./prefijo).Creo que tengo este. Llego tarde a la fiesta, pero creo que algunos apreciarán que esté aquí si se encuentran con este hilo. Los comentarios deberían explicar:
fuente
Estas son formas cortas de obtener información del script:
Carpetas y archivos:
Usando estos comandos:
Y obtuve esta salida:
Ver también: https://pastebin.com/J8KjxrPF
fuente
Esto funciona en bash-3.2:
Si tiene un
~/bindirectorio en su$PATH, tieneAdentro de este directorio. Se origina el guión~/bin/lib/B. Usted sabe dónde está el script incluido en relación con el original, en ellibsubdirectorio, pero no dónde está en relación con el directorio actual del usuario.Esto se resuelve con lo siguiente (dentro
A):No importa dónde esté el usuario o cómo llame al script, esto siempre funcionará.
fuente
whiches muy discutible.type,hashY otras órdenes internas hacen la misma cosa mejor en bash.whiches un poco más portátil, aunque en realidad no es el mismo que sewhichusa en otros shells como tcsh, que lo tiene como un generador incorporado.whichAl ser una herramienta externa, no tiene ninguna razón para creer que se comporta de manera idéntica al shell principal.La mejor solución compacta en mi opinión sería:
No hay confianza en nada más que Bash. El uso de
dirname,readlinkybasenameeventualmente conducirá a problemas de compatibilidad, por lo que es mejor evitarlos si es posible.fuente
"$( cd "$( echo "${BASH_SOURCE[0]%/*}/" )"; pwd )". Tendría problemas con el directorio raíz si no lo hace. Además, ¿por qué incluso tienes que usar echo?dirnameybasenameestán estandarizados POSIX, entonces ¿por qué evitar usarlos? Enlaces:dirname,basename