Obtener el último nombre de directorio / nombre de archivo en un argumento de ruta de archivo en Bash

228

Estoy tratando de escribir un enlace post-commit para SVN, que está alojado en nuestro servidor de desarrollo. Mi objetivo es tratar de retirar automáticamente una copia del proyecto comprometido en el directorio donde está alojado en el servidor. Sin embargo, necesito poder leer solo el último directorio en la cadena de directorio pasado al script para poder pagar en el mismo subdirectorio donde están alojados nuestros proyectos.

Por ejemplo, si hago una confirmación SVN al proyecto "ejemplo", mi script obtiene "/ usr / local / svn / repos / example" como primer argumento. Necesito obtener solo "ejemplo" del final de la cadena y luego concatenarlo con otra cadena para poder pasar a "/ server / root / example" y ver los cambios en vivo de inmediato.

TJ L
fuente

Respuestas:

344

basename elimina el prefijo de directorio de una ruta:

$ basename /usr/local/svn/repos/example
example
$ echo "/server/root/$(basename /usr/local/svn/repos/example)"
/server/root/example
algo
fuente
2
basename es definitivamente lo que estoy buscando. ¿Cómo puede obtener el nombre base de un argumento almacenado en una variable? Por ejemploSUBDIR="/path/to/whatever/$(basename $1)"
TJ L
55
@ tj111: suena como si no $1, o $1está vacío
sth
desafortunadamente, si ajusta los comandos, basename no es una buena idea. solo algo a tener en cuenta
dtc
98

El siguiente enfoque se puede utilizar para obtener cualquier ruta de un nombre de ruta:

some_path=a/b/c
echo $(basename $some_path)
echo $(basename $(dirname $some_path))
echo $(basename $(dirname $(dirname $some_path)))

Salida:

c
b
a
Jingguo Yao
fuente
1
no funciona con caminos que tienen espacios ... puedes superar eso con citas ... que de alguna manera funcionaecho "$(basename "$(dirname "$pathname")")"
Ray Foss
75

Bash puede obtener la última parte de una ruta sin tener que llamar al externo basename:

subdir="/path/to/whatever/${1##*/}"
Pausado hasta nuevo aviso.
fuente
2
En mi Mac, el uso de la notación de subcadena es más que un orden de magnitud más rápido que dirname / basename para el caso en el que está haciendo algo trivial a cada uno de unos pocos miles de archivos.
George
1
d=/home/me/somefolder;subdir="/$d/${1##*/}"Terminé con algo como //home/me/somefolder//$ d en realidad proviene de un bucle. El for d in $(find $SOMEFOLDER -maxdepth 1 -type d);uso subdir=$(basename $d)funciona como se esperaba.
Buttle Butkus
1
@ButtleButkus: debe usar en whilelugar de foriterar sobre la salida de find( find -print0 | xargs -0es mejor) o usar globbing: for d in $SOMEFOLDER/*/(la barra final funciona como -type d: puede usar **en Bash 4 para la recursión si lo hace shopt -s globstar, pero un mensaje de "Lista de argumentos demasiado largo" es posible). Tenga en cuenta que la ${1}parte del comando representa el primer argumento de un script o función. Es posible que necesite usar ${d##*/}o alguna otra especificación de variable o argumento o asegurarse de que se pasa un argumento$1
pausa hasta nuevo aviso.
2
@DennisWilliamson Muchas gracias por compartir . Para cualquier lector futuro que empiece a preguntarse por qué no funciona o si yo soy el único estúpido aquí 😂. La respuesta anterior supone que $1contiene the path from which last component is to be taken out. Me perdí esa parte. Mi caso de uso: target_path='/home/user/dir1/dir2/dir3/'; target_path="${target_path%/}"; last_component=${target_path##*/}; echo $last_component- Funciona 😉
Vinay Vissh
2
Vea aquí una explicación de cómo y por qué ${1##*/} funciona: unix.stackexchange.com/a/171786/15070
Matthew