あなたはそれを次のように行うことができます:
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
また、1つまたは2つのドットではなく、そのようなパスで始まる各パスコンポーネントに対して1つまたは2つの余分な先行ドットを印刷します。
で始まるパスコンポーネントに対して複数の文字を実行することについて質問しました.
。それを行うには、とにかく各コンポーネントに個別の注意が必要だと考えました。私は好奇心が強いので、ディレクトリを変更せずに正規のパスを作成することを試みました。いくつかの試行錯誤の後、私は結局それを正しく行う唯一の方法はそれを2回行うことでした-後方と前方:
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
の文字が一の以上のヌルフィールドになります。そのため、複数の連続したスラッシュがnull値の引数に作用します。同じことが$IFS
主人公にも当てはまります。そしてset -- $1
分割するとき、結果$1
がnullの場合はスラッシュで始まり、それ以外の${1:+$PWD}
場合はnullでない場合はを挿入し$PWD
ます。つまり、最初の引数がスラッシュで始まらない場合は、$PWD
先頭に追加されます。これは、パス検証の場合と同じです。
それ以外の場合、最初のfor
ループはパスコンポーネントの順序を次のように再帰的に反転します。
1 2 3
1 2 3
2 1 3
3 2 1
...その間、単一ドットまたはnullコンポーネントは無視されますが、そのため..
に...
1 .. 3
1 .. 3
3
3
... 2番目のパスはこの効果を元に戻し、その間、各コンポーネントを2ドット+チャー、または1ドット+チャー、またはチャーのいずれかに圧縮します。
したがって、存在するかどうかに関係なく、正規のパスに到達するはずです。
2番目のループに少し追加/減算しました。今ではset
それほど頻繁ではなく([!./]*
コンポーネントごとに1回のみ)、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
。ドットは、特定のディレクトリでよく見られるため、どこを見ればよいかが非常にわかりにくい場合があります。