możesz to zrobić w następujący sposób:
cd /usr///.//share/../share//man/man1 || exit
IFS=/; set -f
printf %.1s/ ${PWD%/*}
printf %s\\n "${PWD##*/}"
/u/s/m/man1
a oto 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/
co jest prawie bliskie zrobieniu wszystkich tych samych czynności, które wykonuje funkcja poniżej. nie tworzy skrótów z tyldami ani nie wstawia $PWD
do głowy wiodącego nie-ukośnika, jak robi to funkcja (i w rzeczywistości nigdy nie drukuje początkowego ukośnika), ale można to później obsłużyć. przetwarza komponenty ścieżki zerowej i pojedynczych kropek oraz odsuwa ..
przypadki.
podana ta sama man
ścieżka, jak cd
powyżej, drukuje:
u/s/m/man1
wypisze również jedną lub dwie dodatkowe kropki wiodące dla każdego komponentu ścieżki, który zaczyna się od takiego i nie jest tylko jedną lub dwiema kropkami.
poprosiłeś o zrobienie więcej niż jednego znaku dla komponentu ścieżki zaczynającego się na .
. do tego doszedłem do wniosku, że każdy komponent i tak wymaga indywidualnej uwagi, a ponieważ byłem ciekawy, spróbowałem wypracować kanoniczną ścieżkę bez katalogu zmian. po kilku próbach i błędach ostatecznie zdecydowałem, że jedynym sposobem na zrobienie tego dobrze jest zrobienie tego dwa razy - wstecz i do przodu:
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:--}"
}
tak, że nigdy nie zmienia katalogu ani nie próbuje potwierdzić istnienia żadnego komponentu ścieżki, ale ściska powtarzające się /
separatory i /./
całkowicie usuwa komponenty pojedynczej kropki i odpowiednio przetwarza /../
komponenty podwójnej kropki.
gdy $IFS
jest ustawiony na jakiś znak inny niż biały , sekwencja dwóch lub więcej $IFS
znaków spowoduje jedno lub więcej pustych pól. więc wiele kolejnych ukośników działa na argumenty o wartości zerowej. to samo dotyczy wiodącej $IFS
postaci. a więc kiedy set -- $1
dzieli, jeśli wynik $1
jest pusty, to zaczyna się od ukośnika, w przeciwnym ${1:+$PWD}
razie , jeśli nie jest pusty, wstawiam $PWD
. innymi słowy, jeśli pierwszy argument nie zaczyna się od ukośnika, zostanie $PWD
dodany. jest to tak bliskie, jak w przypadku sprawdzania poprawności ścieżki .
w przeciwnym razie pierwsza for
pętla rekurencyjnie odwraca kolejność składników ścieżki, takich jak:
1 2 3
1 2 3
2 1 3
3 2 1
... robiąc to, ignoruje komponenty jednopunktowe lub zerowe, i ..
robi to ...
1 .. 3
1 .. 3
3
3
... drugie przejście odwraca ten efekt i jednocześnie ściska każdy składnik do 2 kropek + char lub 1-kropka + char lub char .
więc powinno dojść do kanonicznej ścieżki niezależnie od istnienia.
dodałem / odjąłem trochę do drugiej pętli. jest teraz set
rzadziej (tylko raz dla każdego [!./]*
komponentu) i przez case
większość czasu ocenia wzorce zwarć (dzięki wyżej wspomnianemu wzorowi) i obejmuje ocenę dopasowania przywołania ogona ~
. jeśli całość lub część wiodąca (podzielona na całe komponenty) ostatecznie kanonicznej ścieżki mogą się zgadzać ~
, pasujący bit zostanie usunięty i literał ~
zostanie zastąpiony. aby to zrobić, musiałem również zachować pełną kopię ścieżki obok skróconej (ponieważ dopasowanie skróconej ścieżki do ~
prawdopodobnie nie byłoby bardzo pomocne) , więc jest to przechowywane $3
. ostatniwhile
gałąź pętli jest uruchamiana tylko wtedy, gdy ~
jest dopasowana jako podzbiór $3
.
jeśli uruchomisz go z set -x
włączonym śledzeniem, możesz zobaczyć, jak działa.
$ (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
. Kropka jest często tak powszechna w danym katalogu, że stanowi bardzo małą wskazówkę, gdzie należy szukać.