Obtener el nombre del directorio actual (sin ruta completa) en un script Bash

Respuestas:

1118

No necesita basename, y especialmente no necesita una subshell que ejecute pwd (que agrega una operación de horquilla adicional y costosa ); el shell puede hacer esto internamente usando la expansión de parámetros :

result=${PWD##*/}          # to assign to a variable

printf '%s\n' "${PWD##*/}" # to print to stdout
                           # ...more robust than echo for unusual names
                           #    (consider a directory named -e or -n)

printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
                           # ...useful to make hidden characters readable.

Tenga en cuenta que si está aplicando esta técnica en otras circunstancias (no PWD, pero alguna otra variable que contenga un nombre de directorio), es posible que deba recortar las barras diagonales finales. A continuación se utiliza el soporte extglob de bash para trabajar incluso con múltiples barras diagonales:

dirname=/path/to/somewhere//
shopt -s extglob           # enable +(...) glob syntax
result=${dirname%%+(/)}    # trim however many trailing slashes exist
result=${result##*/}       # remove everything before the last / that still remains
printf '%s\n' "$result"

Alternativamente, sin extglob:

dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}"                  # remove everything before the last /
Charles Duffy
fuente
31
¿Cuál es la diferencia entre $ {PWD ## * /} y $ PWD?
Mr_Chimp
24
@Mr_Chimp the first es una operación de expansión de parámetros que recorta el resto del directorio para proporcionar solo el nombre base. Tengo un enlace en mi respuesta a la documentación sobre la expansión de parámetros; siéntase libre de seguir eso si tiene alguna pregunta.
Charles Duffy
24
@stefgosselin $PWDes el nombre de una variable bash incorporada; Todos los nombres de variables incorporados están en mayúsculas (para distinguirlos de las variables locales, que siempre deben tener al menos un carácter en minúscula). result=${PWD#*/}Cómo no valorar a /full/path/to/directory; en su lugar, despoja solo el primer elemento, haciéndolo path/to/directory; El uso de dos #caracteres hace que el patrón coincida con la codicia, haciendo coincidir tantos caracteres como sea posible. Lea la página de expansión de parámetros, vinculada en la respuesta, para más información.
Charles Duffy
55
Tenga en cuenta que el resultado de pwdno siempre es el mismo que el valor de $PWD, debido a las complicaciones que surgen de cdla conexión a través de enlaces simbólicos, si bash tiene la -o physicalopción establecida, etc. Esto solía volverse especialmente desagradable en el manejo de directorios montados automáticamente, donde grabar la ruta física en lugar de la lógica produciría una ruta que, si se usa, permitiría al automontador desmontar espontáneamente el directorio que estaba usando.
Alex North-Keys
3
¡Agradable! Alguien debería escribir un libro para los viejos tipos de conchas de Borne como yo. Tal vez hay uno por ahí? Podría tener un crotchity viejos Administración de Sistemas diciendo cosas como, "en mis tiempos sólo shy cshy si queríamos la tecla de retroceso para trabajar había que leer toda la sttypágina hombre, y nos gustó!"
Red Cricket
336

Usa el basenameprograma. Para su caso:

% basename "$PWD"
bin
Arkady
fuente
20
¿No es este el propósito del basenameprograma? ¿Qué hay de malo en esta respuesta además de faltar las comillas?
Nacht - Restablece a Mónica el
11
@Nacht basenamees de hecho un programa externo que hace lo correcto, pero el funcionamiento de cualquier programa externo para una fiesta que se puede hacer fuera de la caja utilizando solamente funcionalidad integrada es tonto, incurriendo impacto en el rendimiento ( fork(), execve(), wait(), etc.) para Sin razón.
Charles Duffy
3
... como un aparte, mis objeciones basenameaquí no se aplican dirname, porque dirnametiene una funcionalidad que ${PWD##*/}no lo hace, transformando una cadena sin barras ., por ejemplo. Por lo tanto, si bien el uso dirnamecomo herramienta externa tiene una sobrecarga de rendimiento, también tiene una funcionalidad que ayuda a compensarlo.
Charles Duffy
44
@LouisMaddox, un poco de kibitzing: la functionpalabra clave es incompatible con POSIX sin agregar ningún valor sobre la sintaxis estandarizada, y la falta de comillas crearía errores en los nombres de directorio con espacios. wdexec() { "./$(basename "$PWD")"; }podría ser una alternativa preferible.
Charles Duffy
28
Claro que usar basenamees menos "eficiente". Pero probablemente sea más eficiente en términos de productividad del desarrollador porque es fácil de recordar en comparación con la sintaxis de bash feo. Entonces, si lo recuerdas, hazlo. De lo contrario, basenamefunciona igual de bien. ¿Alguien ha tenido que mejorar el "rendimiento" de un script bash y hacerlo más eficiente?
usr
139
$ echo "${PWD##*/}"

​​​​​

DigitalRoss
fuente
2
@jocap ... excepto que el uso de echo allí, sin citar el argumento, es incorrecto . Si el nombre del directorio tiene múltiples espacios, o un carácter de tabulación, se contraerá en un solo espacio; Si tiene un carácter comodín, se expandirá. El uso correcto sería echo "${PWD##*/}".
Charles Duffy
99
@jocap ... además, no estoy seguro de que "echo" sea de hecho una parte legítima de la respuesta. La pregunta era cómo obtener la respuesta, no cómo imprimir la respuesta; si el objetivo fuera asignarlo a una variable, por ejemplo, name=${PWD##*/}sería correcto y name=$(echo "${PWD##*/}")sería incorrecto (en un sentido de ineficiencia innecesaria).
Charles Duffy el
24

Puede usar una combinación de pwd y basename. P.ej

#!/bin/bash

CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`

echo "$BASENAME"

exit;
mbelos
fuente
18
Por favor no. Los backticks crean una subshell (por lo tanto, una operación de horquilla), y en este caso, ¡los estás usando dos veces ! [Como una objeción adicional, aunque estilística, los nombres de las variables deben estar en minúsculas a menos que los exporte al entorno o sean un caso especial y reservado].
Charles Duffy, el
11
y, como segundo estilo, los backs de quibble deben ser reemplazados por $ (). todavía se bifurca pero es más legible y se necesita menos excaping.
Jeremy Wall
1
Por convención, las variables de entorno (PATH, EDITOR, SHELL, ...) y las variables internas de shell (BASH_VERSION, RANDOM, ...) están totalmente en mayúsculas. Todos los demás nombres de variables deben estar en minúsculas. Dado que los nombres de las variables distinguen entre mayúsculas y minúsculas, esta convención evita anular accidentalmente las variables ambientales e internas.
Rany Albeg Wein
2
Depende de la convención. Se podría argumentar que todas las variables de shell son variables de entorno (dependiendo del shell) y, por lo tanto, todas las variables de shell deben estar en mayúsculas. Alguien más podría argumentar en función del alcance: las variables globales son mayúsculas, mientras que las variables locales son minúsculas, y todas son globales. Otro podría argumentar que hacer que las variables sean mayúsculas agrega una capa adicional de contraste con los comandos que ensucian los scripts de shell, que también son todas palabras cortas pero significativas en minúsculas. Puedo / no puedo / estoy de acuerdo / con cualquiera de esos argumentos, pero he visto los tres en uso. :)
dannysauer
17

¿Qué tal grep:

pwd | grep -o '[^/]*$'
naranja
fuente
no lo recomendaría porque parece obtener información sobre el color, mientras pwd | xargs basenameque no ... probablemente no es tan importante, pero la otra respuesta es más simple y más consistente en todos los entornos
davidhq
8

Me gusta la respuesta seleccionada (Charles Duffy), pero tenga cuidado si está en un directorio con enlace simbólico y desea el nombre del directorio de destino. Desafortunadamente, no creo que se pueda hacer en una expresión de expansión de un solo parámetro, tal vez me equivoque. Esto debería funcionar:

target_PWD=$(readlink -f .)
echo ${target_PWD##*/}

Para ver esto, un experimento:

cd foo
ln -s . bar
echo ${PWD##*/}

informa "bar"

DIRNAME

Para mostrar los directorios iniciales de una ruta (sin incurrir en un fork-exec de / usr / bin / dirname):

echo ${target_PWD%/*}

Esto, por ejemplo, transformará foo / bar / baz -> foo / bar

FDS
fuente
55
Desafortunadamente, readlink -fes una extensión de GNU y, por lo tanto, no está disponible en los BSD (incluido OS X).
Xiong Chiamiov
8
echo "$PWD" | sed 's!.*/!!'

Si está utilizando Bourne Shell o ${PWD##*/}no está disponible.

anómalo
fuente
44
Para su información, ${PWD##*/}es POSIX sh: todo moderno / bin / sh (incluido el tablero, ceniza, etc.) lo admite; para llegar a Bourne real en una caja reciente, necesitarías estar en un sistema Solaris ligeramente antiguo. Más allá de eso - echo "$PWD"; omitir las comillas conduce a errores (si el nombre del directorio tiene espacios, caracteres comodín, etc.).
Charles Duffy
1
Sí, estaba usando un viejo sistema Solaris. He actualizado el comando para usar comillas.
anomal
7

Este hilo es genial! Aquí hay un sabor más:

pwd | awk -F / '{print $NF}'
rodvlopes
fuente
5

Sorprendentemente, nadie mencionó esta alternativa que usa solo comandos bash incorporados:

i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"

Como una ventaja adicional , puede obtener fácilmente el nombre del directorio principal con:

[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"

Estos funcionarán en Bash 4.3-alpha o más reciente.

Arton Dorneles
fuente
sorprendentemente? Sólo bromeando, pero otros son mucho más corto y más fácil de recordar
codewandler
Esto es bastante divertido = P No había oído hablar de $ IFS (separador de campo interno) antes de esto. mi golpe era demasiado viejo, pero puedo probarlo aquí: jdoodle.com/test-bash-shell-script-online
Stan Kurdziel
5

Utilizar:

basename "$PWD"

O

IFS=/ 
var=($PWD)
echo ${var[-1]} 

Convierta el separador de nombre de archivo interno (IFS) de nuevo al espacio.

IFS= 

Hay un espacio después del IFS.

Fuego en el cielo
fuente
4
basename $(pwd)

o

echo "$(basename $(pwd))"
usuario3278975
fuente
2
Necesita más comillas para ser correcto: tal como está, la salida de pwdse divide en cadenas y se expande globalmente antes de pasar a basename.
Charles Duffy
Por lo tanto, basename "$(pwd)"aunque eso es muy ineficiente en comparación con solo basename "$PWD", lo que en sí mismo es ineficiente en comparación con el uso de una expansión de parámetros en lugar de llamar basenameen absoluto.
Charles Duffy
4

Para los jinetes de búsqueda como yo:

find $PWD -maxdepth 0 -printf "%f\n"
usuario2208522
fuente
Cambie $PWDa "$PWD"para manejar correctamente los nombres de directorio inusuales.
Charles Duffy
3

generalmente uso esto en scripts sh

SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder

puedes usar esto para automatizar cosas ...

Gloria holandesa
fuente
readlink: illegal option -- f usage: readlink [-n] [file ...]
2

Debajo de grep con regex también funciona,

>pwd | grep -o "\w*-*$"
Abhishek Gurjar
fuente
3
No funciona si el nombre del directorio contiene caracteres "-".
daniula
1

Solo usa:

pwd | xargs basename

o

basename "`pwd`"
marcos
fuente
2
Esta es, en todos los aspectos, una versión peor de la respuesta dada anteriormente por Arkady ( stackoverflow.com/a/1371267/14122 ): la xargsformulación es ineficaz y tiene errores cuando los nombres de directorio contienen nuevas líneas literales o caracteres de comillas, y la segunda formulación llama al pwdcomando en una subshell, en lugar de recuperar el mismo resultado a través de una expansión variable incorporada.
Charles Duffy
@CharlesDuffy Sin embargo, es una respuesta válida y práctica a la pregunta.
bachph
1

Si desea ver solo el directorio actual en la región de solicitud de bash, puede editar el .bashrcarchivo ~. Cambiar \wa \Wen la línea:

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

correr source ~/.bashrc y solo mostrará el nombre del directorio en la región de solicitud.

Ref: /superuser/60555/show-only-current-directory-name-not-full-path-on-bash-prompt

Gautam Sreekumar
fuente
0

Puede usar la utilidad basename que elimina cualquier prefijo que termine en / y el sufijo (si está presente en una cadena) de la cadena e imprime el resultado en la salida estándar.

$basename <path-of-directory>
niks_4143
fuente
0

Prefiero usar gbasename, que es parte de GNU coreutils.

Steve Benner
fuente
Para su información, no viene con mi distribución de Ubuntu.
Katastic Voyage
@KatasticVoyage, está allí en Ubuntu, solo se llama basenameallí. Por lo general, solo se llama gbasenameen MacOS y otras plataformas que de lo contrario se envían con un nombre base no GNU.
Charles Duffy
-1

Los siguientes comandos darán lugar a la impresión de su directorio de trabajo actual en un script bash.

pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR
Paul Sabou
fuente
2
(1) No estoy seguro de dónde estamos asegurando que la lista de argumentos sea tal que $1contendrá el directorio de trabajo actual. (2) El pushdy popdno sirve para nada aquí porque cualquier cosa dentro de los backticks se realiza en una subshell, por lo que no puede afectar el directorio del shell principal para empezar. (3) El uso "$(cd "$1"; pwd)"sería más legible y resistente frente a los nombres de directorio con espacios en blanco.
Charles Duffy