Вы можете сделать это так:
cd /usr///.//share/../share//man/man1 || exit
IFS=/; set -f
printf %.1s/ ${PWD%/*}
printf %s\\n "${PWD##*/}"
/u/s/m/man1
и вот 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/
это довольно близко к тому, чтобы делать все то же самое, что функция делает ниже. он не сокращается с тильдами и не вставляет в $PWDголову для начального не косой черты, как функция (и фактически никогда не печатает начальную косую черту), но это может быть обработано впоследствии. он обрабатывает компоненты с нулевым путем и одноточечные, и отсеивает ..случаи.
по тому же manпути, что и cdвыше, он печатает:
u/s/m/man1
он также напечатает одну или две дополнительные начальные точки для каждого компонента пути, который начинается с такового, а не просто одну или две точки.
Вы спрашивали о том, чтобы сделать больше, чем один символ для компонента пути, начинающегося с .. чтобы сделать это, я решил, что каждый компонент в любом случае будет нуждаться в индивидуальном внимании, и, поскольку мне было любопытно, я попробовал свои силы в разработке канонического пути без каталога изменений. после некоторой проб и ошибок я в итоге решил, что единственный способ сделать это правильно - это сделать это дважды - вперед и назад:
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:--}"
}
таким образом, он никогда не изменяет каталог и не пытается подтвердить существование какого-либо компонента пути, но он сжимает повторяющиеся /разделители и полностью удаляет компоненты, состоящие из /./одной точки, и соответствующим образом обрабатывает /../компоненты с двумя точками.
Когда $IFSдля некоторого непробельного символа задано значение , последовательность из двух или более $IFSсимволов приведет к появлению одного или нескольких пустых полей. поэтому множественные последовательные слэши работают с нулевыми аргументами. То же самое верно для главного $IFSгероя. и поэтому при set -- $1разбиении, если полученное значение $1равно нулю, оно начинается с косой черты, иначе, ${1:+$PWD}если оно не равно нулю, то я вставляю $PWD. другими словами, если первый аргумент не начинается с косой черты, он будет $PWDдобавлен. это настолько близко, насколько это касается проверки пути .
в противном случае первый forцикл рекурсивно инвертирует порядок компонентов пути, например:
1 2 3
1 2 3
2 1 3
3 2 1
... при этом он игнорирует любые одноточечные или нулевые компоненты, и для ..этого делает ...
1 .. 3
1 .. 3
3
3
... второй проход отменяет этот эффект, и при этом он сжимает каждый компонент либо в 2 точки + символ , либо в 1 точку + символ , либо в символ .
поэтому он должен идти по каноническому пути независимо от существования.
Я добавил / вычитал немного во второй цикл. теперь это происходит setреже (только один раз для каждого [!./]*компонента) и caseбольшую часть времени выполняет оценку шаблонов коротких замыканий (благодаря вышеупомянутому шаблону) , а также включает в себя оценку соответствия по хвостовому вызову ~. если все или начальная часть (разделенная на целые компоненты) окончательно канонического пути могут совпадать ~, совпадающий бит будет удален и ~будет заменен литерал . чтобы сделать это, я должен был сохранить полную копию пути вместе с сокращенным (поскольку сопоставление сокращенного пути, ~вероятно, не очень помогло бы) , и поэтому это сохраняется $3. последнийwhileветви петли выполняется только тогда , когда ~подобран как подмножество $3.
если вы запустите его с set -xвключенной трассировкой, вы можете посмотреть, как он работает.
$ (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. Точка часто настолько распространена в определенном каталоге, что является очень маленькой подсказкой, куда вы должны смотреть.