vous pouvez le faire comme:
cd /usr///.//share/../share//man/man1 || exit
IFS=/; set -f
printf %.1s/ ${PWD%/*}
printf %s\\n "${PWD##*/}"
/u/s/m/man1
et voici un sed
:
printf %s "$file" |
tr /\\n \\n/ | sed -et$ \
-e '\|^\.\.$|{x;s|\(.*\)\n.*$|\1|;x;}' \
-e 's|^\.\{0,2\}$||;\|.|H;$!d;x' \
-e$ -e '\|\(\.\{0,2\}.\)\(.*\)\(\n\)|!b' \
-e 's||\1\3\2\3|;P;s|\n||;D' |
tr /\\n \\n/
qui est assez proche de faire toutes les mêmes choses que la fonction ci-dessous. il n'abrège pas de tildes ni n'insère le $PWD
dans la tête pour une non-barre oblique comme le fait la fonction (et en fait, n'imprime jamais la barre oblique) mais cela pourrait être géré par la suite. il traite les composants de chemin nul et les points uniques et élimine les ..
cas.
étant donné le même man
chemin que cd
ci-dessus, il imprime:
u/s/m/man1
il imprimera également un ou deux points de tête supplémentaires pour chaque composant de chemin commençant par tel et non pas seulement un ou deux points.
vous avez demandé de faire plus que le seul caractère d'un composant de chemin commençant par un .
. pour ce faire, je pensais que chaque composant aurait besoin d'une attention individuelle de toute façon, et parce que j'étais curieux, j'ai essayé de trouver un chemin canonique sans le répertoire de changement. après quelques essais et erreurs, j'ai finalement décidé que la seule façon de le faire correctement était de le faire deux fois - en arrière et en avant:
pathbytes(){
local IFS=/ o="$-" p
set -f${ZSH_VERSION+LFy}
set -- ${1:-$PWD}
for p in /${1:+$PWD} $*
do case $p in (.|"") ;;
(..) ${1+shift} ;;
(/) set -- ;;
(*) set -- $p $*; esac
done
for p in //$* ""
do case ${p:-/$3} in
([!./]*) ;;
(..*) set "..$@" ;;
(.*) set ".$@" ;;
(//*) ! set "" $1 $1 ;;
(~) ! p=\~ ;;
(~/*) p="~/$2";set $HOME
! while "${2+shift}" 2>&3
do p="~/${p#??*/}"
done 3>/dev/null;;
esac&& set "" "${p%"${p#$1?}"}/$2" "$p/$3"
done; printf %s\\n "${p:-$2}"
set +f "-${o:--}"
}
de sorte que ne modifie jamais le répertoire ou n'essaie pas de confirmer l'existence d'un composant de chemin, mais il serre les /
délimiteurs répétés et supprime /./
entièrement les composants à point unique, et traite /../
les composants à double point de manière appropriée.
lorsque $IFS
est défini sur un caractère non blanc , une séquence de deux caractères ou plus $IFS
se traduira par un ou plusieurs champs nuls. donc plusieurs barres obliques consécutives entraînent des arguments de valeur nulle. il en va de même pour un $IFS
personnage principal . et donc quand set -- $1
se divise, si le résultat $1
est nul alors il a commencé par une barre oblique, sinon, ${1:+$PWD}
s'il n'est pas nul, alors j'insère $PWD
. en d'autres termes, si le premier argument ne commence pas par une barre oblique, il sera $PWD
ajouté au début . c'est aussi proche que cela vient de la validation du chemin .
sinon, la première for
boucle inverse récursivement l'ordre des composants du chemin, comme:
1 2 3
1 2 3
2 1 3
3 2 1
... ce faisant, il ignore tous les composants à point unique ou nul, et pour ..
cela ...
1 .. 3
1 .. 3
3
3
... le deuxième passage inverse cet effet, et ce faisant , il comprime chaque composant soit 2-points + carbonisation , ou 1-Dot + carbonisation ou de carbonisation .
il devrait donc fonctionner sur un chemin canonique indépendamment de l'existence.
j'ai ajouté / soustrait un peu à la deuxième boucle. elle est désormais set
moins fréquente (une seule fois pour chaque [!./]*
composant) , et court-circuite les case
évaluations de modèles la plupart du temps (grâce au modèle susmentionné) , et inclut une évaluation de correspondance d'appel final ~
. si tout ou une partie principale (divisée sur des composants entiers) du chemin finalement canonique peut correspondre ~
, le bit correspondant sera supprimé et un littéral ~
sera substitué. Pour ce faire, j'ai dû également conserver une copie complète du chemin à côté de l'abrégé (car faire correspondre le chemin abrégé à ~
ne serait probablement pas très utile) , et donc cela est conservé $3
. le dernierwhile
la branche de boucle n'est exécutée que si elle ~
correspond à un sous-ensemble de $3
.
si vous l'exécutez avec set -x
trace activée, vous pouvez le regarder fonctionner.
$ (set -x;pathbytes ..abc/def/123///././//.././../.xzy/mno)
+ pathbytes ..abc/def/123///././//.././../.xzy/mno
+ local IFS=/ o=xsmi p
+ set -f
+ set -- ..abc def 123 . . .. . .. .xzy mno
+ set --
+ set -- home
+ set -- mikeserv home
+ set -- ..abc mikeserv home
+ set -- def ..abc mikeserv home
+ set -- 123 def ..abc mikeserv home
+ shift
+ shift
+ set -- .xzy ..abc mikeserv home
+ set -- mno .xzy ..abc mikeserv home
+ set mno mno
+ set . mno mno
+ set .x/mno .xzy/mno
+ set .. .x/mno .xzy/mno
+ set ..a/.x/mno ..abc/.xzy/mno
+ set m/..a/.x/mno mikeserv/..abc/.xzy/mno
+ set h/m/..a/.x/mno home/mikeserv/..abc/.xzy/mno
+ p=~/h/m/..a/.x/mno
+ set home mikeserv
+ shift
+ p=~/m/..a/.x/mno
+ shift
+ p=~/..a/.x/mno
+
+ printf %s\n ~/..a/.x/mno
~/..a/.x/mno
+ set +f -xsmi
/f/b/.c/wizard_magic
. Le point est souvent si commun dans un répertoire particulier qu'il est un très petit indice de l'endroit où vous devriez chercher.