Étant donné deux spécifications de chemin Unix absolues , on pourrait décomposer chaque spécification comme la concaténation d'un préfixe commun le plus long et d'un suffixe spécifique. Par exemple,
/abc/bcd/cdf -> /abc/bcd + cdf
/abc/bcd/chi/hij -> /abc/bcd + chi/hij
Existe-t-il un ou plusieurs utilitaires Unix pour calculer une telle décomposition ? (J'ai ajouté "ou utilitaires" au cas où il existe des utilitaires distincts pour calculer le préfixe commun le plus long et pour calculer les chemins relatifs.)
(Je me rends compte qu'il ne serait pas extrêmement difficile de coder de tels utilitaires, mais j'essaie de privilégier les outils plus ou moins standards par rapport aux outils sur mesure, dans la mesure du possible.)
J'écris "path spec" plutôt que "path" pour éviter des problèmes comme l'existence (des chemins) dans un système de fichiers donné, des liens, etc.
Réponse acceptée :
Vous pouvez le faire dans une boucle shell. Le code ci-dessous devrait fonctionner avec toutes sortes de chemins étranges avec des barres obliques supplémentaires ; si tous vos chemins sont de la forme /foo/bar
, vous pouvez vous en sortir avec quelque chose de plus 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
}
Vous pouvez également déterminer le préfixe commun le plus long des deux chaînes et le réduire à son dernier /
caractère (sauf lorsque le préfixe commun est uniquement constitué de barres obliques).