puedes hacerlo como:
cd /usr///.//share/../share//man/man1 || exit
IFS=/; set -f
printf %.1s/ ${PWD%/*}
printf %s\\n "${PWD##*/}"
/u/s/m/man1
y aquí hay 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/
eso se acerca bastante a hacer las mismas cosas que la función hace a continuación. no se abrevia con tildes ni se inserta $PWD
en la cabeza para una barra no inicial como lo hace la función (y, de hecho, nunca imprime la barra diagonal), pero eso podría manejarse después. procesa componentes de ruta nula y puntos únicos, y elimina los ..
casos.
dada la misma man
ruta que la cd
anterior imprime:
u/s/m/man1
también imprimirá uno o dos puntos iniciales adicionales para cada componente de ruta que comience con tal y no sea solo uno o dos puntos.
usted preguntó por hacer más que el comienzo de caracteres para un trayecto de componente con una .
. para hacerlo, pensé que cada componente necesitaría atención individual de todos modos, y como tenía curiosidad, intenté descifrar una ruta canónica sin el directorio de cambio. Después de un poco de prueba y error, finalmente decidí que la única forma de hacerlo bien era hacerlo dos veces, hacia atrás y hacia adelante:
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:--}"
}
para que nunca cambie el directorio o intente confirmar la existencia de algún componente de ruta, pero exprime /
delimitadores repetidos y descarta /./
por completo los componentes de un solo punto, y procesa /../
los componentes de doble punto de manera apropiada.
cuando $IFS
se establece en algún carácter que no sea un espacio en blanco , una secuencia de dos o más $IFS
caracteres dará como resultado uno o más campos nulos. por lo que varias barras inclinadas consecutivas resultan en argumentos de valor nulo. Lo mismo es cierto para un $IFS
personaje principal . y así, cuando se set -- $1
divide, si el resultado $1
es nulo, entonces comenzó con una barra, de lo contrario, ${1:+$PWD}
si no es nulo, entonces lo inserto $PWD
. en otras palabras, si el primer argumento no comienza con una barra inclinada, se $PWD
antepondrá. eso es lo más cercano a la validación de ruta .
de lo contrario, el primer for
bucle invierte recursivamente el orden de los componentes de la ruta, como:
1 2 3
1 2 3
2 1 3
3 2 1
... mientras lo hace, ignora cualquier componente de punto único o nulo, y para ..
ello ...
1 .. 3
1 .. 3
3
3
... la segunda pasada invierte este efecto, y mientras lo hace, exprime cada componente a 2 puntos + char , o 1 punto + char , o char .
por lo que debería funcionar en un camino canónico independientemente de la existencia.
Agregué / resté un poco al segundo bucle. ahora set
es menos frecuente (solo una vez para cada [!./]*
componente) , y las case
evaluaciones de patrones de cortocircuitos la mayor parte del tiempo (gracias al patrón mencionado anteriormente) , e incluye una evaluación de coincidencia de llamada de cola contra ~
. si todas o una parte inicial (como se divide en componentes completos) de la ruta canónica finalmente puede coincidir ~
, el bit de coincidencia se eliminará y ~
se sustituirá un literal . Para hacer esto, tuve que mantener una copia completa de la ruta junto a la abreviada (porque hacer coincidir la ruta abreviada con ~
probablemente no sería muy útil) , y así se mantiene $3
. el últimowhile
La rama de bucle solo se ejecuta si ~
coincide con un subconjunto de $3
.
si lo ejecuta con el set -x
rastreo habilitado, puede verlo funcionar.
$ (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
. El punto es a menudo tan común en un directorio particular que puede ser una pista muy pequeña de dónde debería estar buscando.