script programas programacion pasar parametros ejemplos comandos bash path

bash - programas - programacion en shell



Una forma confiable para que un script Bash obtenga la ruta completa a sí mismo (23)

Obtener la ruta absoluta de un script de shell

No utiliza la opción -f en el enlace de lectura y, por lo tanto, debería funcionar en BSD / Mac OS X.

Ayudas

  • source ./script (cuando es llamado por el operador de punto)
  • Ruta absoluta / ruta / a / script
  • Ruta relativa como ./script
  • /path/dir1/../dir2/dir3/../script
  • Cuando se llama desde symlink
  • Cuando el enlace simbólico está anidado, por ejemplo, foo->dir1/dir2/bar bar->./../doe doe->script
  • Cuando la persona que llama cambia el nombre de los scripts

Estoy buscando casos de esquina donde este código no funciona . Por favor hagamelo saber.

Código

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

Emisión conocida

El script debe estar en el disco en alguna parte . Deja que sea a través de una red. Si intenta ejecutar este script desde un PIPE no funcionará

wget -o /dev/null -O - http://host.domain/dir/script.sh |bash

Técnicamente hablando, está indefinido. En la práctica, no hay una forma sensata de detectar esto. (Un co-proceso no puede acceder al entorno del padre).

Esta pregunta ya tiene una respuesta aquí:

Tengo un script de Bash que necesita conocer su ruta completa. Estoy tratando de encontrar una manera ampliamente compatible de hacerlo sin terminar con caminos de aspecto familiar o moderno. Solo necesito apoyar Bash, no sh, csh, etc.

Lo que he encontrado hasta ahora:

  1. La respuesta aceptada para Obtener el directorio de origen de un script Bash desde direcciones es obtener la ruta del script a través de dirname $0 , lo cual está bien, pero puede devolver una ruta relativa (como . ), Que es un problema si desea cambiar Los directorios en el script y tienen la ruta de acceso todavía apuntan al directorio del script. Aún así, dirname será parte del rompecabezas.

  2. La respuesta aceptada a la ruta absoluta del script de Bash con OS X (específico de OS X, pero la respuesta funciona independientemente) proporciona una función que probará si $0 parece relativo y si es así, prepagará $PWD . Pero el resultado aún puede contener bits relativos (aunque en general es absoluto); por ejemplo, si el script está t en el directorio /usr/bin y está en /usr y escribe bin/../bin/t para ejecutarlo (sí, eso es complicado), terminas con /usr/bin/../bin como la ruta del directorio del script. Que funciona , pero ...

  3. La solución de readlink en esta página , que se ve así:

    # Absolute path to this script. /home/user/bin/foo.sh SCRIPT=$(readlink -f $0) # Absolute path this script is in. /home/user/bin SCRIPTPATH=`dirname $SCRIPT`

    Pero readlink no es POSIX y, al parecer, la solución se basa en el readlink de readlink de GNU, donde los BSD no funcionan por alguna razón (no tengo acceso a un sistema similar a BSD para verificar).

Entonces, varias formas de hacerlo, pero todas tienen sus advertencias.

¿Cuál sería una mejor manera? Donde "mejor" significa:

  • Me da el camino absoluto.
  • Extrae bits funky incluso cuando se los invoca de manera complicada (vea el comentario en el # 2 arriba). (Por ejemplo, al menos moderadamente canonicaliza el camino.)
  • Se basa solo en Bash-isms o cosas que seguramente se encuentran en los sabores más populares de los sistemas * nix (GNU / Linux, BSD y sistemas similares a BSD como OS X, etc.).
  • Evita llamar a programas externos si es posible (por ejemplo, prefiere los elementos integrados de Bash).
  • ( Actualizado , gracias por el wich ). No tiene que resolver los enlaces simbólicos (de hecho, preferiría que los dejara solos, pero eso no es un requisito).

¿Fácil de leer? A continuación se muestra una alternativa. Ignora los enlaces simbólicos.

#!/bin/bash currentDir=$( cd $(dirname "$0") pwd ) echo -n "current " pwd echo script $currentDir


Como realpath no está instalado por defecto en mi sistema Linux, lo siguiente funciona para mí:

SCRIPT="$(readlink --canonicalize-existing "$0")" SCRIPTPATH="$(dirname "$SCRIPT")"

$SCRIPT contendrá la ruta del archivo real al script y $SCRIPTPATH la ruta real del directorio que contiene el script.

Antes de usar esto lee los comentarios de esta respuesta .


Esto es lo que he encontrado (edición: más algunos ajustes proporcionados por sfstewman , levigroker , Kyle Strand y Rob Kennedy ), que parece que se ajustan principalmente a mi "mejor" criterio:

SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"

Esa línea SCRIPTPATH parece particularmente indirecta, pero la necesitamos en lugar de SCRIPTPATH=`pwd` para manejar adecuadamente los espacios y enlaces simbólicos.

Tenga en cuenta también que las situaciones esotéricas, como la ejecución de un script que no proviene de un archivo en un sistema de archivos accesible (lo que es perfectamente posible), no se atienden allí (o en cualquiera de las otras respuestas que he visto). ).


He utilizado el siguiente enfoque con éxito durante un tiempo (aunque no en OS X), y solo usa un shell incorporado y maneja el caso ''source foobar.sh'' por lo que he visto.

Un problema con el siguiente código de ejemplo (apresurado) es que la función usa $ PWD que puede o no ser correcta en el momento de la llamada a la función. Así que eso necesita ser manejado.

#!/bin/bash function canonical_path() { # Handle relative vs absolute path [ ${1:0:1} == ''/'' ] && x=$1 || x=$PWD/$1 # Change to dirname of x cd ${x%/*} # Combine new pwd with basename of x echo $(pwd -P)/${x##*/} cd $OLDPWD } echo $(canonical_path "${BASH_SOURCE[0]}") type [ type cd type echo type pwd


Hemos colocado nuestro propio producto realpath-lib en GitHub para uso comunitario gratuito y sin compromiso.

Enchufe descarado pero con esta biblioteca Bash puedes:

get_realpath <absolute|relative|symlink|local file>

Esta función es el núcleo de la biblioteca:

function get_realpath() { if [[ -f "$1" ]] then # file *must* exist if cd "$(echo "${1%/*}")" &>/dev/null then # file *may* not be local # exception is ./file.ext # try ''cd .; cd -;'' *works!* local tmppwd="$PWD" cd - &>/dev/null else # file *must* be local local tmppwd="$PWD" fi else # file *cannot* exist return 1 # failure fi # reassemble realpath echo "$tmppwd"/"${1##*/}" return 0 # success }

No requiere ninguna dependencia externa, solo Bash 4+. También contiene funciones para get_dirname , get_filename , get_stemname y validate_path validate_realpath . Es gratis, limpio, simple y bien documentado, por lo que también se puede utilizar para fines de aprendizaje, y sin duda se puede mejorar. Pruébalo a través de plataformas.

Actualización: Después de algunas revisiones y pruebas, hemos reemplazado la función anterior con algo que logra el mismo resultado (sin usar dirname, solo Bash puro) pero con una mejor eficiencia:

function get_realpath() { [[ ! -f "$1" ]] && return 1 # failure : file does not exist. [[ -n "$no_symlinks" ]] && local pwdp=''pwd -P'' || local pwdp=''pwd'' # do symlinks. echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result. return 0 # success }

Esto también incluye una configuración de entorno no_symlinks que proporciona la capacidad de resolver enlaces simbólicos al sistema físico. Por defecto, mantiene los enlaces simbólicos intactos.


La forma más sencilla que he encontrado para obtener una ruta canónica completa en Bash es usar cd y pwd :

ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

El uso de ${BASH_SOURCE[0]} lugar de $0 produce el mismo comportamiento independientemente de si el script se invoca como <name> o source <name> .


La solución aceptada tiene el inconveniente (para mí) de no ser "fuente-capaz":
si lo llama desde " source ../../yourScript ", $0 sería " bash "!

La siguiente función (para bash> = 3.0) me da la ruta correcta, sin embargo, la secuencia de comandos podría llamarse (directamente oa través de la source , con una ruta absoluta o relativa):
(por "ruta correcta", me refiero a la ruta absoluta completa del script al que se llama , incluso cuando se llama desde otra ruta, directamente o con " source ")

#!/bin/bash echo $0 executed function bashscriptpath() { local _sp=$1 local ascript="$0" local asp="$(dirname $0)" #echo "b1 asp ''$asp'', b1 ascript ''$ascript''" if [[ "$asp" == "." && "$ascript" != "bash" && "$ascript" != "./.bashrc" ]] ; then asp="${BASH_SOURCE[0]%/*}" elif [[ "$asp" == "." && "$ascript" == "./.bashrc" ]] ; then asp=$(pwd) else if [[ "$ascript" == "bash" ]] ; then ascript=${BASH_SOURCE[0]} asp="$(dirname $ascript)" fi #echo "b2 asp ''$asp'', b2 ascript ''$ascript''" if [[ "${ascript#/}" != "$ascript" ]]; then asp=$asp ; elif [[ "${ascript#../}" != "$ascript" ]]; then asp=$(pwd) while [[ "${ascript#../}" != "$ascript" ]]; do asp=${asp%/*} ascript=${ascript#../} done elif [[ "${ascript#*/}" != "$ascript" ]]; then if [[ "$asp" == "." ]] ; then asp=$(pwd) ; else asp="$(pwd)/${asp}"; fi fi fi eval $_sp="''$asp''" } bashscriptpath H export H=${H}

La clave es detectar el caso " source " y usar ${BASH_SOURCE[0]} para recuperar el script real.


Más simplemente, esto es lo que funciona para mí:

MY_DIR=`dirname $0` source $MY_DIR/_inc_db.sh


Me sorprende que el comando realpath no haya sido mencionado aquí. Mi entendimiento es que es ampliamente portátil / portado.

Su solución inicial se convierte en:

SCRIPT=`realpath $0` SCRIPTPATH=`dirname $SCRIPT`

Y para dejar los enlaces simbólicos sin resolver según su preferencia:

SCRIPT=`realpath -s $0` SCRIPTPATH=`dirname $SCRIPT`


Otra forma de hacer esto:

shopt -s extglob selfpath=$0 selfdir=${selfpath%%+([!/])} while [[ -L "$selfpath" ]];do selfpath=$(readlink "$selfpath") if [[ ! "$selfpath" =~ ^/ ]];then selfpath=${selfdir}${selfpath} fi selfdir=${selfpath%%+([!/])} done echo $selfpath $selfdir


Prueba esto:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))


Puedes intentar definir la siguiente variable:

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

O puedes probar la siguiente función en Bash:

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

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

Relacionado:


Quizás la respuesta aceptada a la siguiente pregunta pueda ser de ayuda.

¿Cómo puedo obtener el comportamiento de readlink -f de GNU en una Mac?

Dado que solo desea canonizar el nombre que obtiene al concatenar $ PWD y $ 0 (asumiendo que $ 0 no es absoluto para empezar), solo use una serie de reemplazos de abs_dir=${abs_dir////./////} regulares a lo largo de la línea de abs_dir=${abs_dir////./////} y tal.

Sí, sé que se ve horrible, pero funcionará y es puro Bash.


Respondiendo esta pregunta muy tarde, pero uso:

SCRIPT=$( readlink -m $( type -p $0 )) # Full path to script BASE_DIR=`dirname ${SCRIPT}` # Directory script is run in NAME=`basename ${SCRIPT}` # Actual name of script even if linked


Si usamos Bash, creo que esta es la forma más conveniente ya que no requiere llamadas a ningún comando externo:

THIS_PATH="${BASH_SOURCE[0]}"; THIS_DIR=$(dirname $THIS_PATH)


Simplemente:

BASEDIR=$(readlink -f $0 | xargs dirname)

Los operadores de lujo no son necesarios.


Solo por el gusto de hacerlo, he hecho un poco de pirateo de un script que hace cosas puramente textuales, puramente en Bash. Espero haber capturado todos los casos de borde.

Tenga en cuenta que el ${var//pat/repl} que mencioné en la otra respuesta no funciona, ya que no puede hacer que reemplace solo la coincidencia más corta posible, lo cual es un problema para reemplazar /foo/../ como por ejemplo, /*/../ tomará todo lo que está delante de él, no solo una entrada. Y dado que estos patrones no son realmente expresiones regulares, no veo cómo se puede hacer que funcione. Así que aquí está la solución bien intrincada que se me ocurrió, disfrutar. ;)

Por cierto, avíseme si encuentra algún caso de borde no manejado.

#!/bin/bash canonicalize_path() { local path="$1" OIFS="$IFS" IFS=$''/'' read -a parts < <(echo "$path") IFS="$OIFS" local i=${#parts[@]} local j=0 local back=0 local -a rev_canon while (($i > 0)); do ((i--)) case "${parts[$i]}" in ""|.) ;; ..) ((back++));; *) if (($back > 0)); then ((back--)) else rev_canon[j]="${parts[$i]}" ((j++)) fi;; esac done while (($j > 0)); do ((j--)) echo -n "/${rev_canon[$j]}" done echo } canonicalize_path "/.././..////../foo/./bar//foo/bar/.././bar/../foo/bar/./../..//../foo///bar/"



Teniendo en cuenta este problema de nuevo: hay una solución muy popular a la que se hace referencia en este hilo que tiene su origen here :

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

Me he mantenido alejado de esta solución debido al uso de dirname: puede presentar dificultades entre plataformas, especialmente si un script necesita ser bloqueado por razones de seguridad. Pero como una alternativa pura de Bash, ¿qué hay de usar:

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

¿Sería esta una opción?


Un trazador de líneas

`dirname $(realpath $0)`


Utilizar:

SCRIPT_PATH=$(dirname `which $0`)

which imprime en la salida estándar la ruta completa del ejecutable que se habría ejecutado cuando el argumento pasado se ingresó en el indicador de comandos del shell (que es lo que contiene $ 0)

dirname el sufijo no de directorio de un nombre de archivo.

Por lo tanto, terminas con la ruta completa del script, sin importar si la ruta fue especificada o no.


Bourne shell ( sh ) forma compatible:

SCRIPT_HOME=`dirname $0 | while read a; do cd $a && pwd && break; done`