質問でメモしたのと同じ出力を得るために必要なのはこれだけです:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
ゆがめる必要はありません。これらの2行は、POSIX互換性に近いものを装ったシェルですべて実行します。
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
しかし、私はこれが好きだった。そして、私はこの仕事を少し良くするものの基礎を示したかった。それで私はこれを少し編集しました。私/tmp
は今のところそれを立ち往生しているが、私も自分でそれを維持するつもりだと思う。ここにあります:
cat /tmp/prompt
プロンプトスクリプト:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
注:最近yashを知ったので、昨日作成しました。何らかの理由で、すべての引数の最初のバイトを%c
文字列で印刷しません-ドキュメントはその形式のワイド文字拡張について特定されていたので、おそらく関連しています-しかし、それはうまくいきます%.1s
それがすべてです。そこには2つの主なことがあります。そして、これは次のようになります。
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 >
パーシング $PWD
$PS1
評価されるたび$PWD
に、プロンプトに追加するために解析および出力されます。しかし、私は$PWD
画面全体が混み合っているのが好きではないので、現在のパスにあるすべてのパンくずリストの最初の文字だけを、現在のディレクトリまで表示します。このような:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
ここにはいくつかの手順があります。
IFS=/
現在の値を分割する必要が$PWD
あり、そのための最も信頼できる方法は$IFS
split onを使用すること/
です。後でそれを気にする必要はありません-これ以降のすべての分割$@
は、次のようなコマンドのシェルの位置パラメータ配列によって定義されます:
set -- ${PWD%"${last=${PWD##/*/}}"}
この1つは少しトリッキーですが、主なものは、我々している分裂ということであるので、$PWD
上の/
シンボル。また、パラメーター拡張を使用し$last
て、左端と右端の/
スラッシュの間にある値の後にすべてを割り当てます。このようにして、私がちょうど/
1人だけいて、1人しかいない/
場合$last
でも、全体$PWD
と等しく$1
なり、空になることを知っています。これは重要です。また$last
、$PWD
に割り当てる前にの末尾から削除し$@
ます。
printf "${1+%c/}" "$@"
だからここに-限り${1+is set}
、私たちprintf
最初の%c
各たちのシェルの引数のharacter -私達はちょうど私たちの現在の各ディレクトリに設定しました$PWD
-レストップディレクトリ-に分割/
。したがって、基本的に$PWD
は、最上位以外のすべてのディレクトリの最初の文字を印刷するだけです。場合にのみ起こる実現するためにかかわらず、それは重要だ$1
ルートに起こらないであろう、まったく設定されます/
または1でから取り出し/
などのように/etc
。
printf "$last > "
$last
最上位ディレクトリに割り当てたばかりの変数です。これが今、私たちのトップディレクトリです。最後のステートメントが実行したかどうかを出力します。そして、それは>
適切な測定のために少しきれいになります。
しかし、インクリメントについてはどうですか?
そして、$PS2
条件の問題があります。以前にこれをどのように行うことができるかを示しましたが、それは以下で見つけることができます-これは基本的にスコープの問題です。しかし、多くのprintf \b
ackspaces を始めてから、キャラクター数のバランスをとろうとしない限り、それはもう少しあります...うーん。だから私はこれをします:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
繰り返しますが、日を${parameter##expansion}
節約します。しかし、ここでは少し奇妙です。実際に変数を設定し、それ自体を削除します。新しい値-ストリップの中央に設定-を削除するグロブとして使用します。分かりますか?私たちは、##*
から何もすることができ、最後の文字に、当社の増分変数の先頭からすべてを取り除きます[$((PS2c=0))-9]
。この方法で値を出力しないことが保証されていますが、それでも値を割り当てています。それはかなりクールです-私は前にそれをやったことがありません。しかし、POSIXは、これが最も移植性の高い方法であることも保証します。
そして、${parameter} $((expansion))
これらの定義を評価する場所に関係なく、別のサブシェルに設定することなく、現在のシェルにこれらの定義を保持するPOSIX指定のおかげです。で、それが動作する理由、これがあるdash
とsh
、それがでないばかりだけでなく、bash
とzsh
。シェル/ターミナルに依存するエスケープを使用せず、変数に自分自身をテストさせます。それが移植可能なコードを迅速にするものです。
残りは非常に単純です- もう一度リセット$PS2
されるまで$PS1
、評価されるたびにカウンターをインクリメントするだけです。このような:
PS2='$((PS2c=PS2c+1)) > '
だから今私は次のことができます:
ダッシュデモ
ENV=/tmp/prompt dash -i
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 > printf '\t%s\n' "$PS1" "$PS2" "$PS2c"
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
0
/u/s/m/man3 > cd ~
/h/mikeserv >
SHデモ
bash
またはで同じ動作をしsh
ます:
ENV=/tmp/prompt sh -i
/h/mikeserv > cat <<HEREDOC
1 > $( echo $PS2c )
2 > $( echo $PS1 )
3 > $( echo $PS2 )
4 > HEREDOC
4
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
/h/mikeserv > echo $PS2c ; cd /
0
/ > cd /usr/share
/u/share > cd ~
/h/mikeserv > exit
上で述べたように、主な問題は、計算をどこで行うかを考慮する必要があるということです。親シェルで状態を取得しないので、そこで計算しません。サブシェルで状態を取得します-それが計算の場所です。ただし、親シェルで定義を行います。
ENV=/dev/fd/3 sh -i 3<<\PROMPT
ps1() { printf '$((PS2c=0)) > ' ; }
ps2() { printf '$((PS2c=PS2c+1)) > ' ; }
PS1=$(ps1)
PS2=$(ps2)
PROMPT
0 > cat <<MULTI_LINE
1 > $(echo this will be line 1)
2 > $(echo and this line 2)
3 > $(echo here is line 3)
4 > MULTI_LINE
this will be line 1
and this line 2
here is line 3
0 >
man 1 mktemp
。