状態保存 bash 機能

状態保存 bash 機能

各呼び出しごとにカウントを増やす(および返す)関数をBashに実装したいと思います。残念ながら、これはサブシェル内で関数を呼び出すので、親シェルの変数を変更できないため、これはマイナーなようではありません。

私の試みは次のとおりです。

PS_COUNT=0

ps_count_inc() {
    let PS_COUNT=PS_COUNT+1
    echo $PS_COUNT
}

ps_count_reset() {
    let PS_COUNT=0
}

これは次のように使用されます(したがって、サブシェルで関数を呼び出す必要があります)。

PS1='$(ps_count_reset)> '
PS2='$(ps_count_inc)   '

これにより、番号付きの複数行のプロンプトが表示されます。

> echo 'this
1   is
2   a
3   test'

愛らしい。しかし、上記の制限のために動作しません。

うまくいかない解決策は、変数の代わりにファイルに数を書き込むことです。ただし、これは同時に実行される複数のセッション間で競合を引き起こす可能性があります。もちろん、ファイル名にシェルのプロセスIDを追加することもできます。しかし、私は多くのファイルのために私のシステムが複雑にならないより良い解決策が欲しいです。

ベストアンサー1

ここに画像の説明を入力してください。

質問で確認したのと同じ結果を得るには、次のようにします。

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)) > '

注:最近学んだ。ヤッシュ、昨日作りました。何らかの理由で文字列を使用して各引数の最初のバイトを印刷しないでください%c。文書はその形式のワイド文字拡張に固有であるため、関連がある可能性があります。%.1s

それはすべてです。そこでは大きく二つのことが起こりました。次のようになります。

/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分割を使用することです/。その後、全く気にする必要はありません。ここからのすべての分割は、$@次のコマンドでシェルの位置引数の配列によって定義されます。たとえば、次のようになります。

set -- ${PWD%"${last=${PWD##/*/}}"}

だからこれは少しトリッキーですが、最も重要なのは、$PWDシンボルによって分かれているということです。また、パラメータ拡張を使用して、一番左のスラッシュと一番右のスラッシュの間に表示される値の後にすべてを/割り当てます。そうすれば、私がちょうど入ったのですが、1つだけあればまだ全体と同じで空であることがわかります。これは重要です。また、に割り当てる前にの尾から削除します。$last///$last$PWD$1$last$PWD$@

printf "${1+%c/}" "$@"

${1+is set}したがって、ここでは、各シェルパラメータのprintf最初の文字(現在のディレクトリのすべてのディレクトリ(最上位ディレクトリを除く)%cに設定)を分割できる限りです。したがって、デフォルトでは、最上位ディレクトリを除くすべてのディレクトリの最初の文字を印刷します。ただし、これは設定されたときにのみ発生し、ルートまたは。$PWD/$PWD$1///etc

printf "$last > "

$last一番上のディレクトリに割り当てた変数です。今これが最上位のディレクトリです。最後のステートメントが実行されたかどうかを印刷します。>良い結果を得るには少しきれいさが必要です。

しかし、増分はどうですか?

その後、条件の問題があります$PS2。以前はこれを行う方法を説明しましたが、以下で引き続き見つけることができます。これは基本的に範囲の問題です。しかし、それよりも多くのことがあります。多くのprintf \backspace作業を始めてから、文字数のバランスを取ろうとしない限り…こんな。だから私はこうします:

PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'

${parameter##expansion}一日をまた保存しました。ところで、ここに奇妙なことがあります。実際に変数自体を削除しながら変数を設定しているということです。新しい値(mid-strip設定)を削除するglobとして使用します。願いより?##*増分変数の先頭から最後の文字(任意の文字になることがあります)まで、すべての文字を削除します[$((PS2c=0))-9]。これにより、値は出力されませんが、まだ割り当てられます。素敵ですね。私はそのようなことを一度もしたことがありません。しかし、POSIXはこれが最も移植性の高い方法であることを保証します。

${parameter} $((expansion))これは、評価の場所に関係なく、別のサブシェルに設定する必要はなく、現在のシェルにこれらの定義を保持するPOSIX条項のおかげです。これがdashまさに内外と同様に内外でもうまく機能する理由ですsh。シェル/ターミナル関連のエスケープを使用せず、変数に自分自身をテストさせます。これが移植可能なコードの理由です。bashzsh高速。

残りはとても簡単です。リセットされる$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 >

上海デモ

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 >

おすすめ記事