Dadas dos especificaciones absolutas de ruta Unix , uno podría descomponer cada especificación como la concatenación de un prefijo común más largo y un sufijo específico. Por ejemplo,
/abc/bcd/cdf -> /abc/bcd + cdf
/abc/bcd/chi/hij -> /abc/bcd + chi/hij
¿Existe una utilidad (o utilidades) de Unix para calcular dicha descomposición? (Agregué "o utilidades" en caso de que haya utilidades separadas para calcular el prefijo común más largo y para calcular rutas relativas).
(Me doy cuenta de que no sería extremadamente difícil codificar tales utilidades, pero trato de dar prioridad a las herramientas que son más o menos estándar sobre las hechas a medida, siempre que sea posible).
Escribo "especificación de ruta" en lugar de "ruta" para evitar problemas como la existencia (de las rutas) en un sistema de archivos dado, enlaces, etc.
Respuesta aceptada:
Puedes hacer eso en un bucle de shell. El siguiente código debería funcionar con todo tipo de caminos extraños con barras inclinadas adicionales; si todas sus rutas son de la forma /foo/bar
, puedes salirte con la tuya con algo más simple.
split_common_prefix () {
path1=$1
path2=$2
common_prefix=
## Handle initial // specially
case $path1 in
//[!/]*) case $path2 in
//[!/]*) common_prefix=/ path1=${path1#/} path2=${path2#/};;
*) return;;
esac;;
/*) case $path2 in
/*) :;;
*) return;;
esac;;
*) case $path2 in /*) return;; esac;;
esac
## Normalize multiple slashes
trailing_slash1= trailing_slash2=
case $path1 in */) trailing_slash1=/;; esac
case $path2 in */) trailing_slash2=/;; esac
path1=$(printf %s/ "$path1" | tr -s / /)
path2=$(printf %s/ "$path2" | tr -s / /)
if [ -z "$trailing_slash1" ]; then path1=${path1%/}; fi
if [ -z "$trailing_slash2" ]; then path2=${path2%/}; fi
## Handle the complete prefix case (faster, necessary for equality and
## for some cases with trailing slashes)
case $path1 in
"$path2")
common_prefix=$path1; path1= path2=
return;;
"$path2"/*)
common_prefix=$path2; path1=${path1#$common_prefix} path2=
return;;
esac
case $path2 in
"$path1"/*)
common_prefix=$path1; path1= path2=${path2#$common_prefix}
return;;
esac
## Handle the generic case
while prefix1=${path1%%/*} prefix2=${path2%%/*}
[ "$prefix1" = "$prefix2" ]
do
common_prefix=$common_prefix$prefix1/
path1=${path1#$prefix1/} path2=${path2#$prefix1/}
done
}
Alternativamente, determine el prefijo común más largo de las dos cadenas y recórtelo a su último /
carácter (excepto cuando el prefijo común consta únicamente de barras).