resueltos - shell script ejemplos
Unix shell script descubre en qué directorio reside el archivo de script? (15)
BASE_DIR = "$ (cd" $ (dirname "$ 0") "; pwd)"; echo "$ BASEDIR"
Básicamente, necesito ejecutar el script con rutas relacionadas con la ubicación del archivo de script de shell, ¿cómo puedo cambiar el directorio actual al mismo directorio donde reside el archivo de script?
Como sugiere theMarko:
BASEDIR=$(dirname $0)
echo $BASEDIR
Esto funciona a menos que ejecute el script desde el mismo directorio donde reside el script, en cuyo caso obtendrá un valor de ''''.
Para solucionar ese problema use:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = ''.'' ]
then
script_dir="$current_dir"
fi
Ahora puede usar la variable current_dir a lo largo de su script para referirse al directorio del script. Sin embargo, esto todavía puede tener el problema del enlace simbólico
En Bash, deberías obtener lo que necesitas así:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
Eso debería hacer el truco:
echo `pwd`/`dirname $0`
Puede parecer feo dependiendo de cómo se invocó y del cwd, pero debería llevarlo a donde necesita ir (o puede modificar la cadena si le importa cómo se ve).
Este one-liner le dice dónde está el script de shell, no importa si lo ejecutó o si lo obtuvo . Además, resuelve cualquier enlace simbólico involucrado, si ese es el caso:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
Por cierto, supongo que estás usando / bin / bash .
Hagamos que sea un oneliner POSIX:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Probado en muchos shells compatibles con Bourne, incluidos los BSD.
Por lo que sé, soy el autor y lo puse en dominio público. Para obtener más información, consulte: https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
Inspirado por share
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
La mejor respuesta para esta pregunta fue respondida aquí:
Obtener el directorio de origen de un script Bash desde dentro
Y es:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
One-liner que le dará el nombre completo del directorio del script, sin importar desde dónde se lo llame.
Para entender cómo funciona puedes ejecutar el siguiente script:
#!/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''"
La publicación original contiene la solución (ignorar las respuestas, no agregan nada útil). El trabajo interesante lo realiza el mencionado enlace de readlink
comandos de Unix con la opción -f
. Funciona cuando el script es llamado por un absoluto así como por una ruta relativa.
Para bash, sh, ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
Para tcsh, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
Consulte también: https://.com/a/246128/59087
Si estás usando bash ...
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
Suponiendo que estás usando bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
Este script debe imprimir el directorio en el que se encuentra y luego el directorio en el que se encuentra el script. Por ejemplo, cuando lo llama desde /
con el script en /home/mez/
, genera
/
/home/mez
Recuerde, cuando asigne variables de la salida de un comando, ajuste el comando en $(
y )
, o no obtendrá la salida deseada.
Tantas respuestas, todas plausibles, cada una con objetivos de pros y contras y ligeramente diferentes (lo que probablemente debería indicarse para cada una). Aquí hay otra solución que cumple con el objetivo principal de ser claro y trabajar en todos los sistemas, en todo bash (sin suposiciones sobre las versiones de bash, o las opciones de pwd
readlink
o pwd
), y razonablemente hace lo que se espera que suceda (por ejemplo, resolviendo enlaces simbólicos). es un problema interesante, pero generalmente no es lo que realmente quiere), manejar casos de borde como espacios en rutas, etc., ignora cualquier error y usa un sano juicio por defecto si hay algún problema.
Cada componente se almacena en una variable separada que puede usar individualmente:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script''s name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
Un comentario anterior sobre una respuesta lo dijo, pero es fácil perderse entre todas las otras respuestas.
Cuando se utiliza bash:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
INTRODUCCIÓN
Esta respuesta corrige la respuesta muy rota pero sorprendentemente mejor votada de este hilo (escrito por TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
¿POR QUÉ UTILIZAR dirname "$ 0" EN SU PROPIA NO FUNCIONA?
dirname $ 0 solo funcionará si el usuario inicia el script de una manera muy específica. Pude encontrar varias situaciones en las que esta respuesta falla y bloquea el script.
En primer lugar, vamos a entender cómo funciona esta respuesta. Está obteniendo el directorio de script haciendo
dirname "$0"
$ 0 representa la primera parte del comando que llama a la secuencia de comandos (es básicamente el comando ingresado sin los argumentos:
/some/path/./script argument1 argument2
$ 0 = "/ some / path /./ script"
dirname básicamente encuentra el último / en una cadena y lo trunca allí. Así que si lo haces:
dirname /usr/bin/sha256sum
obtendrá: / usr / bin
Este ejemplo funciona bien porque / usr / bin / sha256sum es una ruta con el formato correcto pero
dirname "/some/path/./script"
no funcionaría bien y te daría:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Digamos que estás en el mismo directorio que tu script y lo ejecutas con este comando
./script
$ 0 en esta situación será ./script y dirname $ 0 dará:
. #or BASEDIR=".", again this will crash your script
Utilizando:
sh script
Sin ingresar la ruta completa también se dará un BASEDIR = "."
Usando directorios relativos:
../some/path/./script
Da un nombre de directorio $ 0 de:
../some/path/.
Si está en el directorio / some y llama al script de esta manera (tenga en cuenta la ausencia de / al principio, nuevamente una ruta relativa):
path/./script.sh
Obtendrá este valor para dirname $ 0:
path/.
y ./path/./script (otra forma de la ruta relativa) da:
./path/.
Las únicas dos situaciones en las que basedir $ 0 funcionará si el usuario usa sh o touch para iniciar un script porque ambas darán como resultado $ 0:
$0=/some/path/script
lo que te dará una ruta que puedes usar con dirname.
LA SOLUCIÓN
Debería tener en cuenta y detectar cada una de las situaciones mencionadas anteriormente y aplicar una solución si surge:
#!/bin/bash
#this script will only work in bash, make sure it''s installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "/$0=$0";fi
#The line below detect script''s parent directory. $0 is the part of the launch command that doesn''t contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo ''BASEDIR=$(dirname "$0") gives: ''"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
cd $(dirname $(readlink -f $0))