Dis que j'ai deux chemins: <source_path>
et <target_path>
. Je voudrais que ma coquille (ZSH) puisse automatiquement savoir s'il existe un moyen de représenter <target_path>
de <source_path>
comme un chemin relatif.
Par exemple. Assumons
<source_path>
est /foo/bar/something
<target_path>
est /foo/hello/world
Le résultat serait ../../hello/world
J'ai besoin de créer un lien symbolique de <source_path>
à <target_path>
Utilisation d'un relatif liaison symbolique dans la mesure du possible, car notre serveur Samba n'affiche pas correctement le fichier lorsque j'accumule ces fichiers sur le réseau à partir de Windows (je ne suis pas l'administrateur SYS, et ne le faites pas avoir le contrôle de ce réglage)
En admettant que <target_path>
et <source_path>
sont des chemins absolus, ce qui suit crée un lien symbolique pointant vers un chemin absol.
ln -s <target_path> <source_path>
donc, cela ne fonctionne pas pour mes besoins. J'ai besoin de le faire pour des centaines de fichiers, donc je ne peux pas simplement le réparer manuellement.
Toute coquille intégrée qui s'occupe de cela?
Vous pouvez utiliser la commande symlinks
pour convertir des chemins absolus en relatif:
/tmp$ mkdir -p 1/{a,b,c} 2
/tmp$ cd 2
/tmp/2$ ln -s /tmp/1/* .
/tmp/2$ ls -l
total 0
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 a -> /tmp/1/a/
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 b -> /tmp/1/b/
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 c -> /tmp/1/c/
Nous avons des liens absolus, les convertissons en relatif:
/tmp/2$ symlinks -cr .
absolute: /tmp/2/a -> /tmp/1/a
changed: /tmp/2/a -> ../1/a
absolute: /tmp/2/b -> /tmp/1/b
changed: /tmp/2/b -> ../1/b
absolute: /tmp/2/c -> /tmp/1/c
changed: /tmp/2/c -> ../1/c
/tmp/2$ ls -l
total 0
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 a -> ../1/a/
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 b -> ../1/b/
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 c -> ../1/c/
Essayez d'utiliser realpath
commande (une partie de GNU coreutils
; > = 8.23 ), par exemple:
realpath --relative-to=/foo/bar/something /foo/hello/world
Si vous utilisez des macos, install GNU Version via: brew install coreutils
et utiliser grealpath
.
Notez que les deux chemins doivent exister pour que la commande réussisse. Si vous avez besoin du chemin relatif de toute façon, même si l'un d'entre eux n'existe pas, ajoutez le commutateur -M.
Pour plus d'exemples, voir Convertir un chemin absolu en chemin relatif donné un répertoire actuel .
Il n'y a pas de shell comité à prendre en charge cela. J'ai trouvé ne solution sur le débordement de pile cependant. J'ai copié la solution ici avec de légères modifications et j'ai marqué cette réponse en tant que wiki communautaire.
relpath() {
# both $1 and $2 are absolute paths beginning with /
# $1 must be a canonical path; that is none of its directory
# components may be ".", ".." or a symbolic link
#
# returns relative path to $2/$target from $1/$source
source=$1
target=$2
common_part=$source
result=
while [ "${target#"$common_part"}" = "$target" ]; do
# no match, means that candidate common part is not correct
# go up one level (reduce common part)
common_part=$(dirname "$common_part")
# and record that we went back, with correct / handling
if [ -z "$result" ]; then
result=..
else
result=../$result
fi
done
if [ "$common_part" = / ]; then
# special case for root (no common path)
result=$result/
fi
# since we now have identified the common part,
# compute the non-common part
forward_part=${target#"$common_part"}
# and now stick all parts together
if [ -n "$result" ] && [ -n "$forward_part" ]; then
result=$result$forward_part
Elif [ -n "$forward_part" ]; then
# extra slash removal
result=${forward_part#?}
fi
printf '%s\n' "$result"
}
Vous pouvez utiliser cette fonction comme si:
source=/foo/bar/something
target=/foo/hello/world
ln -s "$(relpath "$source" "$target")" "$source"
Je pense que ceci python solution (extrait du même poste que la réponse de @ Evaneitelman) mérite également de mentionner. Ajoutez ceci à votre ~/.zshrc
:
relpath() python -c 'import os.path, sys;\
print os.path.relpath(sys.argv[1],sys.argv[2])' "$1" "${2-$PWD}"
Vous pouvez alors faire, par exemple:
$ relpath /usr/local/share/doc/emacs /usr/local/share/fonts
../doc/emacs
Je devais écrire un Bash Script pour faire cela de manière fiable (et bien sûr sans vérifier l'existence de fichiers).
Usage
relpath <symlink path> <source path>
Retourne un chemin source relatif.
exemple:
#/a/b/c/d/e -> /a/b/CC/DD/EE -> ../../CC/DD/EE
relpath /a/b/c/d/e /a/b/CC/DD/EE
#./a/b/c/d/e -> ./a/b/CC/DD/EE -> ../../CC/DD/EE
relpath ./a/b/c/d/e ./a/b/CC/DD/EE
les deux obtiennent ../../CC/DD/EE
Avoir un test rapide, vous pouvez exécuter
curl -sL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath | bash -s -- --test
résultat: une liste de test
/a -> / -> .
/a/b -> / -> ..
/a/b -> /a -> .
/a/b/c -> /a -> ..
/a/b/c -> /a/b -> .
/a/b/c -> /a/b/CC -> CC
/a/b/c/d/e -> /a -> ../../..
/a/b/c/d/e -> /a/b -> ../..
/a/b/c/d/e -> /a/b/CC -> ../../CC
/a/b/c/d/e -> /a/b/CC/DD/EE -> ../../CC/DD/EE
./a -> ./ -> .
./a/b -> ./ -> ..
./a/b -> ./a -> .
./a/b/c -> ./a -> ..
./a/b/c -> ./a/b -> .
./a/b/c -> ./a/b/CC -> CC
./a/b/c/d/e -> ./a -> ../../..
./a/b/c/d/e -> ./a/b/CC -> ../../CC
./a/b/c/d/e -> ./a/b/CC/DD/EE -> ../../CC/DD/EE
/a -> /x -> x
/a/b -> /x -> ../x
/a/b/c -> /x -> ../../x
/a -> /x/y -> x/y
/a/b -> /x/y -> ../x/y
/a/b/c -> /x/y -> ../../x/y
/x -> /a -> a
/x -> /a/b -> a/b
/x -> /a/b/c -> a/b/c
/x/y -> /a -> ../a
/x/y -> /a/b -> ../a/b
/x/y -> /a/b/c -> ../a/b/c
./a a/b/c/d/e -> ./a a/b/CC/DD/EE -> ../../CC/DD/EE
/x x/y y -> /a a/b b/c c -> ../a a/b b/c c
BTW, si vous souhaitez utiliser ce script sans l'enregistrer et que vous faites confiance à ce script, vous avez deux façons de ce faire avec un tour de bash.
Import relpath
comme fonction Bash en suivant la commande suivante. (Exiger Bash 4+)
source <(curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath)
ou appelez le script sur la mouche comme avec Curl Bash Combo.
curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath | bash -s -- /a/b/c/d/e /a/b/CC/DD/EE