Obtener el directorio de origen de un script Bash desde dentro




script linux ejemplos (24)

¿Cómo obtengo la ruta del directorio en el que se encuentra un script de Bash , dentro de ese script?

Por ejemplo, digamos que quiero usar un script Bash como un lanzador para otra aplicación. Quiero cambiar el directorio de trabajo al directorio donde se encuentra el script Bash, para poder operar en los archivos de ese directorio, de esta manera

$ ./application

El comando dirname es el más básico, simplemente analizando la ruta hasta el nombre del archivo fuera de la variable $ 0 (nombre del script):

dirname "$0"

Pero, como señaló Matt B , el camino devuelto es diferente dependiendo de cómo se llame el script. pwd no hace el trabajo porque solo te dice qué es el directorio actual, no qué directorio reside el script. Además, si se ejecuta un enlace simbólico a un script, obtendrás una ruta (probablemente relativa) a donde reside el enlace, no el script real.

Algunos otros han mencionado el comando readlink , pero en su forma más simple, puedes usar:

dirname "$(readlink -f "$0")"

readlink resolverá 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:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

Ejecutando este script en mi directorio de casa, usando una ruta relativa:

>>>$ ./whatdir.sh 
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

De nuevo, pero usando la ruta completa al script:

>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

Ahora cambiando directorios:

>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

Y finalmente usando un enlace simbólico para ejecutar el script:

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat

Esto obtiene el directorio de trabajo actual en Mac OS X 10.6.6:

DIR=$(cd "$(dirname "$0")"; pwd)

Vale la pena mencionar $_ como alternativa a $ 0. Si está ejecutando un script desde bash, la respuesta aceptada se puede acortar a:

DIR="$( dirname "$_" )"

Tenga en cuenta que esta debe ser la primera declaración en su script.


DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"

es un útil de una sola línea que le dará el nombre completo del directorio de la secuencia de comandos sin importar desde 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 multilínea:

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"

Este último funcionará con cualquier combinación de alias, source , bash -c , enlaces simbólicos, etc.

Cuidado: si cd en un directorio diferente antes de ejecutar este fragmento de código, ¡el resultado puede ser incorrecto! Además, ten cuidado con $CDPATH errores de $CDPATH .

Para entender cómo funciona, intente ejecutar este formulario más detallado:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  TARGET="$(readlink "$SOURCE")"
  if [[ $TARGET == /* ]]; then
    echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
    SOURCE="$TARGET"
  else
    DIR="$( dirname "$SOURCE" )"
    echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
    SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
  fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

Y se imprimirá algo como:

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'

SCRIPT_DIR=$( cd ${0%/*} && pwd -P )

La mejor solución compacta en mi opinión sería:

"$( cd "$( echo "${BASH_SOURCE[0]%/*}" )"; pwd )"

No hay confianza en otra cosa que Bash. El uso de dirname, readlinky basenameeventualmente conducirá a problemas de compatibilidad, por lo que es mejor evitarlos si es posible.


Trate de usar:

real=$(realpath $(dirname $0))

Esto debería hacerlo:

DIR=$(dirname "$(readlink -f "$0")")

Trabaja con enlaces simbólicos y espacios en ruta. Vea las páginas del manual para dirname y readlink .

Editar:

Desde la pista de comentarios parece no funcionar con Mac OS. No tengo idea de por qué es eso. ¿Alguna sugerencia?


Esto es específico de Linux, pero podrías usar:

SELF=$(readlink /proc/$$/fd/255)

Use dirname "$0" :

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"

el uso de pwd solo no funcionará si no está ejecutando el script desde el directorio en el que está contenido.

[[email protected] ~]$ pwd
/home/matt
[[email protected] ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[[email protected] ~]$ cd /tmp
[[email protected] tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp

Pruebe la siguiente solución compatible con versiones cruzadas:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

as realpatho los readlinkcomandos no siempre están disponibles (dependiendo del sistema operativo) y ${BASH_SOURCE[0]}está disponible solo en shell bash.

Alternativamente, puedes probar la siguiente función en bash:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

Esta función toma 1 argumento. Si el argumento ya tiene una ruta absoluta, imprímalo tal como está, de lo contrario imprima el $PWDargumento variable + nombre de archivo (sin ./prefijo).

Relacionado:


Ninguno de estos funcionó para un script de bash lanzado por Finder en OS X; terminé usando:

SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"

No es bonito, pero hace el trabajo.


Esto funciona en bash-3.2:

path="$( dirname "$( which "$0" )" )"

Aquí hay un ejemplo de su uso:

Digamos que tienes un directorio ~ / bin , que está en tu $ PATH . Tienes el script A dentro de este directorio. Es fuente s guión ~ / bin / lib / B . Usted sabe dónde está el script incluido es relativo a la original (el subdirectorio lib ), pero no en los que es relativo al directorio actual del usuario.

Esto se resuelve con lo siguiente (dentro de A ):

source "$( dirname "$( which "$0" )" )/lib/B"

No importa dónde esté el usuario o cómo llame al script, esto siempre funcionará.


Respuesta corta:

`dirname $0`

o ( preferably ):

$(dirname "$0")

pwd puede usarse para encontrar el directorio de trabajo actual, y dirname para encontrar el directorio de un archivo en particular (el comando que se ejecutó es $0 , por lo que dirname $0 debería proporcionarle el directorio del script actual).

Sin embargo, dirname proporciona precisamente la parte del directorio del nombre de archivo, que es muy probable que sea relativa al directorio de trabajo actual. Si su script necesita cambiar el directorio por alguna razón, entonces la salida de dirname significado.

Sugiero lo siguiente:

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

De esta manera, obtienes un directorio absoluto, en lugar de relativo.

Dado que el script se ejecutará en una instancia de bash independiente, no es necesario restaurar el directorio de trabajo posteriormente, pero si desea volver a cambiarlo en su script por alguna razón, puede asignar fácilmente el valor de pwd a una variable antes Cambia de directorio, para uso futuro.

Aunque solo

cd `dirname $0`

resuelve el escenario específico en la pregunta, me parece que tener el camino absoluto a más útil en general.


Probé cada uno de estos y ninguno de ellos funcionó. Uno estaba muy cerca pero tenía un pequeño insecto que lo rompió gravemente; se olvidaron de envolver el camino entre comillas.

Además, muchas personas asumen que está ejecutando el script desde un shell, así que olvídese de que cuando abre un nuevo script, se establece de forma predeterminada en su hogar.

Prueba este directorio por tamaño:

/ var / Nadie / Pensamiento / Acerca de los espacios que están / En un directorio / Nombre / Y aquí está su archivo.text

Esto lo hace bien sin importar cómo o dónde lo ejecute.

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

Así que para que sea realmente útil, aquí se explica cómo cambiar al directorio del script en ejecución:

cd "`dirname "$0"`"

Espero que ayude


$(dirname "$(readlink -f "$BASH_SOURCE")")

Aquí hay una sola línea compatible con POSIX:

SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`

# test
echo $SCRIPT_PATH

Hmmm, si en la ruta, basename y dirname simplemente no lo vamos a cortar y recorrer la ruta es difícil (¡y si el padre no exportó PATH!) Sin embargo, el shell debe tener un identificador abierto para su script, y en bash el identificador es # 255.

SELF=`readlink /proc/$$/fd/255`

funciona para mi.


Aquí está la manera simple y correcta:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

Explicación:

  • ${BASH_SOURCE[0]} - la ruta completa al script. El valor de esto será correcto incluso cuando se obtenga el script, por ejemplo, source <(echo 'echo $0') imprime bash , al reemplazarlo con ${BASH_SOURCE[0]} imprimirá la ruta completa del script. (Por supuesto, esto supone que está bien si depende de Bash).

  • readlink -f - Resuelve recursivamente cualquier enlace simbólico en la ruta especificada. Esta es una extensión de GNU, y no está disponible en (por ejemplo) sistemas BSD. Si está ejecutando una Mac, puede usar Homebrew para instalar GNU coreutils y suplantar esto con greadlink -f .

  • Y, por supuesto, dirname obtiene el directorio padre de la ruta.


Una ligera revisión de la solución e-satis y 3bcdnlklvc04a señalada en su respuesta.

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}    

Esto debería seguir funcionando en todos los casos enumerados.

EDIT: prevenir popd después de pushd fallido, gracias a konsolebox


#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`

Yo usaría algo como esto:

# retrieve the full pathname of the called script
scriptPath=$(which $0)

# check whether the path is a link or not
if [ -L $scriptPath ]; then

    # it is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`; 
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

Funciona para todas las versiones, incluyendo

  • cuando se llama a través de enlace flexible de profundidad múltiple,
  • cuando el archivo
  • cuando el script llama por el comando " source " aka . operador (punto).
  • cuando arg $0 se 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í mismo es un enlace simbólico relativo , desea seguirlo y devolver la ruta completa del script enlazado a:

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
if ([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do cd `dirname "$SCRIPT_PATH"`; SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

SCRIPT_PATH se proporciona en la ruta completa, sin importar cómo se llame.
Solo asegúrate de ubicarlo al inicio del script.

Este comentario y código se pueden copiar, licencia seleccionable bajo la GPL2.0 o posterior o CC-SA 3.0 (CreativeCommons Share Alike) o posterior. (c) 2008. Todos los derechos reservados. No hay 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







directory