Cómo verificar si $ PWD es un subdirectorio de una ruta determinada


25

Por ejemplo, verifique si $PWDes un subdirectorio de / home. En otras palabras, estoy buscando una operación de cadena bash para verificar si una cadena comienza con otra.

Respuestas:


26

Si desea probar de manera confiable si un directorio es un subdirectorio de otro, necesitará algo más que una verificación de prefijo de cadena. La respuesta de Gilles describe en detalle cómo hacer esta prueba correctamente.

Pero si desea una simple verificación de prefijo de cadena (¿tal vez ya ha normalizado sus rutas?), Esta es una buena:

test "${PWD##/home/}" != "${PWD}"

Si $PWDcomienza con "/ home /", se elimina en el lado izquierdo, lo que significa que no coincidirá con el lado derecho, por lo que "! =" Devuelve verdadero.


1
+1 perfecto, y para un caso más general: [ "${PWD##$VAR}" != "$PWD" ]Y si esto fuera un [code-golf] ( stackoverflow.com/questions/tagged/code-golf)pregunta me habrías derrotado por dos caracteres ;-) También parece más legible ...
Tobias Kienzler

FWIW, esto también puede ser útil:${PWD/#$HOME/\~}
user1338062

Muy bien, pero ¿qué tal PWD = "/ home /../ etc /"
Alexis Peters

1
@AlexisPeters: Tienes razón: me estaba centrando en la parte del "prefijo de cadena" de la pregunta, y he editado para aclararlo. Gilles ha cubierto muy bien la forma correcta de buscar subdirectorios.
Jander

1
Utilícelo "${PWD%%/subdir*}"para detectar si el usuario se encuentra actualmente en subdirun subdirectorio subdir, ya que %% captura desde el final de la cadena en lugar del principio. Esto debería ser útil para cualquiera que busque más información sobre la sustitución de parámetros: tldp.org/LDP/abs/html/parameter-substitution.html
George Pantazes

33

Para probar si una cadena es un prefijo de otra, en cualquier shell de estilo Bourne:

case $PWD/ in
  /home/*) echo "home sweet home";;
  *) echo "away from home";;
esac

El mismo principio funciona para una prueba de sufijo o subcadena. Tenga en cuenta que en las caseconstrucciones, a diferencia de los nombres de archivo, *coincide con cualquier carácter, incluido uno /o una inicial ..

En shells que implementan la [[ … ]]sintaxis (es decir, bash, ksh y zsh), se puede usar para hacer coincidir una cadena con un patrón. (Tenga en cuenta que el [comando solo puede probar cadenas para la igualdad).

if [[ $PWD/ = /home/* ]]; then 

Si está probando específicamente si el directorio actual está debajo /home, una simple prueba de subcadena no es suficiente, debido a los enlaces simbólicos.

Si /homees un sistema de archivos propio, pruebe si el directorio actual ( .) está en ese sistema de archivos.

if [ "$(df -P . | awk 'NR==2 {print $6}')" = "/home" ]; then
  echo 'The current directory is on the /home filesystem'
fi

Si tiene NetBSD, OpenBSD o GNU (es decir, Linux) readlink, puede usar readlink -fpara quitar enlaces simbólicos de una ruta.

case $(readlink -f .)/ in $(readlink -f /home)/*) 

De lo contrario, puede usar pwdpara mostrar el directorio actual. Pero debe tener cuidado de no utilizar un shell integrado si su shell rastrea los cdcomandos y mantiene el nombre que utilizó para llegar al directorio en lugar de su ubicación "real".

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) 

+1 Gracias por esta respuesta exhaustiva. No tuve en cuenta los enlaces y las peculiaridades del sistema de archivos al preguntar esto, pero definitivamente es bueno saberlo
Tobias Kienzler

8

Versión cruda:

[ ${PWD:0:6} = "/home/" ]

Tiene la desventaja de que primero hay que contar los caracteres y no se puede reemplazar /home/por algo general $1.

editar (gracias @Michael) por la generalización para comparar con $VARuno puede usar

[ "${PWD:0:${#VAR}}" = $VAR ]

44
${#var}es la longitud de $var, por lo que puede generalizar como[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek

@Michael Mrozek ♦: Gracias, funciona perfecto :)
Tobias Kienzler

2

No entiendo muy bien la pregunta, pero para encontrar al padre de $ PWD , sí dirname $PWD. Para buscar el padre del padre, ejecute dirname $(dirname $PWD), etc.


Eso solo funcionaría si supiera la profundidad, de lo contrario termino con /. Ok, podría verificar de forma recursiva, pero ¿no hay algo más fácil?
Tobias Kienzler

1
@tob Si solo supiera la programación de shell ;-)
tshepang

1

Utilizando awk:

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'

+1 por trabajar, pero un poco más lento que una prueba de bash nativa
Tobias Kienzler

0

Hm, es una pena que [no tenga la opción de probar la STRING1 starts with STRING2condición.

Puede intentarlo echo $PWD | grep '^$VAR', pero puede fallar de maneras interesantes cuando VARcontiene símbolos especiales.

awkLa indexfunción de debería poder hacer el truco. Pero todo esto parece demasiado pesado para una cosa tan fácil de probar.


[[regexp para que comience con [[$ PWD = ~ ^ \ / home \ /]]
teknopaul

0

Si se encuentra la parte buscada de la ruta, "vacío" la variable:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.