puoi farlo come:
cd /usr///.//share/../share//man/man1 || exit
IFS=/; set -f
printf %.1s/ ${PWD%/*}
printf %s\\n "${PWD##*/}"
/u/s/m/man1
ed ecco 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/
che si avvicina abbastanza a fare tutte le stesse cose che la funzione fa di seguito. non abbrevia con le tilde né inserisce la $PWD
testina per una non barra iniziale come la funzione (e in realtà non stampa mai la barra iniziale) ma che potrebbe essere gestita in seguito. elabora i componenti del percorso null, i punti singoli e elimina i ..
casi.
dato lo stesso man
percorso di cui cd
sopra stampa:
u/s/m/man1
stamperà anche uno o due punti iniziali extra per ciascun componente del percorso che inizia con tale e non è solo uno o due punti.
hai chiesto di fare più di un carattere per un componente del percorso che inizia con a .
. per farlo ho pensato che ogni componente avrebbe comunque avuto bisogno di attenzione individuale e, dato che ero curioso, ho provato a elaborare un percorso canonico senza la directory di modifica. dopo un po 'di tentativi ed errori alla fine ho deciso che l'unico modo per farlo bene era farlo due volte - avanti e indietro:
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:--}"
}
in modo che non cambi mai la directory o cerchi di confermare l'esistenza di qualsiasi componente del percorso, ma comprime i /
delimitatori ripetuti e rilascia /./
completamente i componenti a punto singolo e elabora /../
i componenti a punto doppio in modo appropriato.
quando $IFS
è impostato su un carattere non bianco , una sequenza di due o più $IFS
caratteri si tradurrà in uno o più campi null. così più barre consecutive si risolvono in argomenti a valore nullo. lo stesso vale per un $IFS
personaggio principale . e così quando si set -- $1
divide, se il risultato $1
è nullo, inizia con una barra, altrimenti, ${1:+$PWD}
se non è nullo, inserisco $PWD
. in altre parole, se il primo argomento non inizia con una barra, verrà $PWD
anteposto. questo è il più vicino possibile alla validazione del percorso .
in caso contrario, il primo for
ciclo inverte in modo ricorsivo l'ordine dei componenti del percorso, come:
1 2 3
1 2 3
2 1 3
3 2 1
... mentre lo fa ignora qualsiasi componente a punto singolo o nullo, e per ..
questo ...
1 .. 3
1 .. 3
3
3
... il secondo passaggio inverte questo effetto e, mentre lo fa, schiaccia ogni componente a 2 punti + carattere , o 1 punto + carattere o carattere .
quindi dovrebbe seguire un percorso canonico indipendentemente dall'esistenza.
ho aggiunto / sottratto un po 'al secondo loop. ora set
è meno frequente (solo una volta per ogni [!./]*
componente) , e la case
maggior parte delle volte esegue la valutazione dei modelli di cortocircuito (grazie al modello sopra menzionato) e include una valutazione della corrispondenza di coda chiamata contro ~
. se tutto o una parte iniziale (come divisa su interi componenti) del percorso finalmente canonico può corrispondere ~
, il bit corrispondente verrà rimosso e ~
verrà sostituito un valore letterale . per fare questo, ho dovuto mantenere una copia completa del percorso insieme anche all'abbreviazione (perché abbinare il percorso abbreviato a ~
probabilmente non sarebbe molto utile) , e quindi questo è mantenuto $3
. l'ultimowhile
il ramo del ciclo viene eseguito solo se ~
corrisponde a un sottoinsieme di $3
.
se lo esegui con la set -x
traccia abilitata, puoi vederlo funzionare.
$ (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
. Il punto è spesso così comune in una directory particolare da essere un indizio molto piccolo su dove dovresti cercare.