bashプロンプトについてのもう1つのクールなストーリー

私はプログラマーです。 少なくとも、それはワークブックに書かれています。 私はほとんどすべての作業時間をコンソールとテキストエディターで過ごします。 私は本当にbashが好きです。 ほぼ1年間、私はzshに住んでいて、多くの同僚や知人のアドバイスを聞いていましたが、最終的にはbashに戻り、後悔していません。











Zshは美しく、快適で、機能的ですが、正直なところ、多くの設定すべてに対処することはできませんでした。 職場環境と戦うのではなく、働きたい。 簡単な例:zshのオートコンプリートにより数回、現在のディレクトリのすべてのディレクトリとファイルを削除しました-zshは、オートコンプリートディレクトリと入力したアスタリスクの間にスペースを置きました(選択したフォルダ内のすべてを削除したかった)。 スペースと/ usrディレクトリを削除するという壮大なバグを覚えていますか? 私も同じことをしました。 おかげで、もう一度助けてくれました。



しかし、それはzshについてではありません-私が少し賢ければ、私はそれを処理し、すべてはうまくいくでしょうが、私たち、厳しいプログラマーはbashとvimを使用し、魅力的なzshとtextmateを流行に敏感な人や他のmodに任せます;)



独創的で普遍的な解決策を書くことはしませんし、与えることもしませんが、私はいつも他の人の構成や説明を読むのが好きで、もし面白い写真が添付されていたら、私はこれらの記事を何度か読み直します。 あなたも興味を持ってくれることを願っています。



突然、私が書いたものから何かを簡単に解決できる場合、またはbashで既に説明されている機能があれば-コメントに書いてください。 まあ、念のために、私の住んでいる場所:

GNU bash, version 4.2.28(2)-release (i386-apple-darwin11.3.0)
      
      









招待前に改行を追加





ですから、私が毎日最初に遭遇すること、そしてbashが気に入らないのは、最後に改行を入れて出力を終了しないコマンドです。 以下に簡単な例を示します(同様の動作をエミュレートします):







もちろん、恐ろしいことは何も起こりませんでしたが、同じzshがこの状況を正しく処理します。bashトリックを教えます。



これを行うには、コマンドライン(PS1)の各プロンプトでカーソル位置を確認し、カーソルが行の最初の文字にない場合は、ラインフィード(文字「\ n」)を表示する必要があります。 カーソルの位置は、エスケープシーケンスを使用して決定できます。

 echo -en "\033[6n" && read -sdR CURPOS
      
      





その結果、CURPOS変数には次のような内容が含まれます。 "^ [[4; 12R"、4は行番号、12は行の文字の番号です。 bash構成に適切なコードを追加します(〜/ .bashrcまたは〜/ .bash_profile):

 # setup color variables color_is_on= color_red= color_green= color_yellow= color_blue= color_white= color_gray= color_bg_red= color_off= if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then color_is_on=true color_red="\[$(/usr/bin/tput setaf 1)\]" color_green="\[$(/usr/bin/tput setaf 2)\]" color_yellow="\[$(/usr/bin/tput setaf 3)\]" color_blue="\[$(/usr/bin/tput setaf 6)\]" color_white="\[$(/usr/bin/tput setaf 7)\]" color_gray="\[$(/usr/bin/tput setaf 8)\]" color_off="\[$(/usr/bin/tput sgr0)\]" color_error="$(/usr/bin/tput setab 1)$(/usr/bin/tput setaf 7)" color_error_off="$(/usr/bin/tput sgr0)" fi function prompt_command { # get cursor position and add new line if we're not in first column exec < /dev/tty local OLDSTTY=$(stty -g) stty raw -echo min 0 echo -en "\033[6n" > /dev/tty && read -sdR CURPOS stty $OLDSTTY [[ ${CURPOS##*;} -gt 1 ]] && echo "${color_error}↵${color_error_off}" } PROMPT_COMMAND=prompt_command
      
      





SM 更新する

PROMPT_COMMANDは、コマンドプロンプトが描画されるたびに呼び出される関数です。 ここで小さなハックが使用されましたが、このハックなしでstackoverflowのコメントで確認しましたが、$ CURPOS変数の値が表示される場合がありました。 花の束に注意を払わないでください-それらはすべて私たちにとって有用です。 構成の結果:







この文字をコマンドが表示するものと区別するために、特に赤い背景が追加されました。 そして、はい、21世紀は庭にあるので、utf番目のロケールを使用します。 廃止されたロケールの場合。 ほとんどの場合、記号「↵」は、zshのように記号「%」などのより単純なものに置き換える必要があります。



gitリポジトリの状態を表示します





コンソールからgitを使用する場合(guiについて話す必要はありません-私たちは古い学校の厳しい開発者です!)gitの現在のブランチとリポジトリの一般的な状態を確認すると便利です-変更されたファイルがあるか、すべてがコミットされています。 すでにこの段階で、2行で構成されるコマンドラインプロンプトを使用する方が便利だという結論に達しました。最初の行には、現在の環境に関する情報(ユーザー、サーバー、作業ディレクトリ、リポジトリに関する情報、および一般的に必要なすべてのものが表示されます) )、および2行目に-直接入力するコマンド。 最初は異常でしたが、今は前のスキームに戻る準備ができていません。geetに関する情報を追加するには、geitのbash-completionとともに表示される特別に訓練された関数__git_ps1を使用できます。







または、独自の「松葉杖」を作成します。 私は2番目の方法に行きました __git_ps1関数は私を満足させませんでした。 まず、ブランチの名前だけでなく、リポジトリの状態も確認したかったのですが、この状態もさまざまな色で強調表示されていました。 第二に、 gitリポジトリを使用して異なるマシン/サーバー間で設定を同期します。このリポジトリのステータスはホームディレクトリでのみ確認しますが、深さに関係なくすべてのサブフォルダでは確認しません。



実際、gitの状態を減算する関数は次のとおりです。

 # get git status function parse_git_status { # clear git variables GIT_BRANCH= GIT_DIRTY= # exit if no git found in system local GIT_BIN=$(which git 2>/dev/null) [[ -z $GIT_BIN ]] && return # check we are in git repo local CUR_DIR=$PWD while [ ! -d ${CUR_DIR}/.git ] && [ ! $CUR_DIR = "/" ]; do CUR_DIR=${CUR_DIR%/*}; done [[ ! -d ${CUR_DIR}/.git ]] && return # 'git repo for dotfiles' fix: show git status only in home dir and other git repos [[ $CUR_DIR == $HOME ]] && [[ $PWD != $HOME ]] && return # get git branch GIT_BRANCH=$($GIT_BIN symbolic-ref HEAD 2>/dev/null) [[ -z $GIT_BRANCH ]] && return GIT_BRANCH=${GIT_BRANCH#refs/heads/} # get git status local GIT_STATUS=$($GIT_BIN status --porcelain 2>/dev/null) [[ -n $GIT_STATUS ]] && GIT_DIRTY=true }
      
      





以前は、変更されたファイル、コミットのインデックスにあるファイル(キャッシュ)、およびリポジトリに属さないファイル(追跡されていない)を解析して個別に出力していましたが、やがてこれは私にとって余分な情報であることに気付きました。 実際、この関数は単純です。gitは通常システムにあることを確認し、gitリポジトリにあることを確認し、ファイルシステムのルートまでのすべてのディレクトリを再帰的に調べ、「。git」フォルダーを探し、現在のブランチの名前を取得して、少なくともコミットされていないファイル。 prompt_commandでこの関数の呼び出しを追加し、プロンプトを作成します。

 function prompt_command { local PS1_GIT= local PWDNAME=$PWD ... # beautify working firectory name if [ $HOME == $PWD ]; then PWDNAME="~" elif [ $HOME == ${PWD:0:${#HOME}} ]; then PWDNAME="~${PWD:${#HOME}}" fi # parse git status and get git variables parse_git_status # build b/w prompt for git [[ ! -z $GIT_BRANCH ]] && PS1_GIT=" (git: ${GIT_BRANCH})" local color_user= if $color_is_on; then # set user color case `id -u` in 0) color_user=$color_red ;; *) color_user=$color_green ;; esac # build git status for prompt if [ ! -z $GIT_BRANCH ]; then if [ -z $GIT_DIRTY ]; then PS1_GIT=" (git: ${color_green}${GIT_BRANCH}${color_off})" else PS1_GIT=" (git: ${color_red}${GIT_BRANCH}${color_off})" fi fi fi # set new color prompt PS1="${color_user}${USER}${color_off}@${color_yellow}${HOSTNAME}${color_off}:${color_white}${PWDNAME}${color_off}${PS1_GIT}\n➜ " }
      
      





最終的には次のようになります。







変数PWDNAMEに関するいくつかの言葉。 はい、「\ w」と書くことができ、すべてが同じになることは知っていますが、prompt_command関数には端末タイトルもあります。

 # set title echo -ne "\033]0;${USER}@${HOSTNAME}:${PWDNAME}"; echo -ne "\007"
      
      





しかし、すでに「\ w」は機能しません。



Python仮想環境の名前を表示する





最近、私が書いている主な言語はPythonです。 彼にとって、 virtualenvと呼ばれる非常に便利なものがあります。 詳細には触れません-これは別の記事のトピックですが、bashコンソールで現在の仮想環境を確認することも非常に便利です。



実際、virtualenvスクリプトは現在のvenvの名前をbash招待状に追加しますが、実際には見苦しくなります。







vertualenvがコマンドラインプロンプトに干渉することを禁止します。

 export VIRTUAL_ENV_DISABLE_PROMPT=1
      
      





そして、好きなようにvenvという名前を自分で印刷します。

 function prompt_command { local PS1_VENV= ... [[ ! -z $VIRTUAL_ENV ]] && PS1_VENV=" (venv: ${VIRTUAL_ENV#$WORKON_HOME})" if $color_is_on; then ... # build python venv status for prompt [[ ! -z $VIRTUAL_ENV ]] && PS1_VENV=" (venv: ${color_blue}${VIRTUAL_ENV#$WORKON_HOME}${color_off})" fi # set new color prompt PS1="${color_user}${USER}${color_off}@${color_yellow}${HOSTNAME}${color_off}:${color_white}\w${color_off}${PS1_GIT}${PS1_VENV}\n➜ " }
      
      











実際、ここではすべてが平凡です。



チームを視覚的に分離する





ターミナルでのかなりアクティブな作業では、特に出力に色が存在する場合、入力コマンドとその実行結果が互いにマージされます。







もちろん、この例はすべてを示すものではありませんが、コンソールで働いていた人は誰でも私が言っていることを理解しています。



私は端末の幅全体に各招待状に水平線を引くことを決めました。このアイデアは報われました-コンソールを使用する方がはるかに便利になりました:







ここに私がそれをする方法があります:

 function prompt_command { ... # build b/w prompt for git and vertial env [[ ! -z $GIT_BRANCH ]] && PS1_GIT=" (git: ${GIT_BRANCH})" [[ ! -z $VIRTUAL_ENV ]] && PS1_VENV=" (venv: ${VIRTUAL_ENV#$WORKON_HOME})" # calculate fillsize local fillsize=$(($COLUMNS-$(printf "${USER}@${HOSTNAME}:${PWDNAME}${PS1_GIT}${PS1_VENV} " | wc -c | tr -d " "))) local FILL=$color_gray while [ $fillsize -gt 0 ]; do FILL="${FILL}─"; fillsize=$(($fillsize-1)); done FILL="${FILL}${color_off}" ... # set new color prompt PS1="${color_user}${USER}${color_off}@${color_yellow}${HOSTNAME}${color_off}:${color_white}${PWDNAME}${color_off}${PS1_GIT}${PS1_VENV} ${FILL}\n➜ " }
      
      





最初に、色のないプロンプト文字列の長さを見つけ、端末幅($ COLUMNS変数)から減算し、ASCII文字「─」で構成されるこの長さの文字列を作成します(ロケールがUnicodeでない場合は、他の文字を使用できます)。



より多くの色



端末が256色をサポートしている場合、標準に制限する必要はありません。

 color_pink="\[$(/usr/bin/tput setaf 99)\]"
      
      











ただし、レガシー端末との互換性のために、これは避けるのが最善です。



あとがきまたは「クールな話、仲間!」





使用環境にかかわらず、作業環境は快適でなければなりません。 Bashは居心地のよいものです。試してみるだけです。 ちなみに、zshを使用しないもう1つの理由は、移動先のサーバーにzshが存在しないことと、そこに配置できないことです。



インターネット上のそのような情報は運送であり、最初(まあ、2番目)のターンでさまざまなシェルを発見したすべての人が、コマンドラインの招待状を設定するために、コメントと端末のセットアップの例を聞きたいです。 そして、はい、ShG、私は知っています;)私はケシ法線=(悲しみ..



スペースを節約するために、構成全体を持ち込むのではなく、誰でもここで見ることができます: github.com/dreadatour/dotfiles.bash_profileファイル)。



UPD :コードは次のとおりです。

 function prompt_command { # get cursor position and add new line if we're not in first column exec < /dev/tty local OLDSTTY=$(stty -g) stty raw -echo min 0 echo -en "\033[6n" > /dev/tty && read -sdR CURPOS stty $OLDSTTY [[ ${CURPOS##*;} -gt 1 ]] && echo "${color_error}↵${color_error_off}" } PROMPT_COMMAND=prompt_command
      
      





sshを中断します。 ハックせずに古いバージョンに戻り、問題を探しています:

 function prompt_command { # get cursor position and add new line if we're not in first column echo -en "\033[6n" && read -sdR CURPOS [[ ${CURPOS##*;} -gt 1 ]] && echo "${color_error}↵${color_error_off}" } PROMPT_COMMAND=prompt_command
      
      







UPD2 :コメントをお寄せいただきありがとうございます-バグの修正、コードの改善。 これで、prompt_command関数は次のようになります。

非表示のテキスト
 # setup color variables color_is_on= color_red= color_green= color_yellow= color_blue= color_white= color_gray= color_bg_red= color_off= color_user= if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then color_is_on=true color_red="\[$(/usr/bin/tput setaf 1)\]" color_green="\[$(/usr/bin/tput setaf 2)\]" color_yellow="\[$(/usr/bin/tput setaf 3)\]" color_blue="\[$(/usr/bin/tput setaf 6)\]" color_white="\[$(/usr/bin/tput setaf 7)\]" color_gray="\[$(/usr/bin/tput setaf 8)\]" color_off="\[$(/usr/bin/tput sgr0)\]" color_error="$(/usr/bin/tput setab 1)$(/usr/bin/tput setaf 7)" color_error_off="$(/usr/bin/tput sgr0)" # set user color case `id -u` in 0) color_user=$color_red ;; *) color_user=$color_green ;; esac fi # some kind of optimization - check if git installed only on config load PS1_GIT_BIN=$(which git 2>/dev/null) function prompt_command { local PS1_GIT= local PS1_VENV= local GIT_BRANCH= local GIT_DIRTY= local PWDNAME=$PWD # beautify working directory name if [[ "${HOME}" == "${PWD}" ]]; then PWDNAME="~" elif [[ "${HOME}" == "${PWD:0:${#HOME}}" ]]; then PWDNAME="~${PWD:${#HOME}}" fi # parse git status and get git variables if [[ ! -z $PS1_GIT_BIN ]]; then # check we are in git repo local CUR_DIR=$PWD while [[ ! -d "${CUR_DIR}/.git" ]] && [[ ! "${CUR_DIR}" == "/" ]] && [[ ! "${CUR_DIR}" == "~" ]] && [[ ! "${CUR_DIR}" == "" ]]; do CUR_DIR=${CUR_DIR%/*}; done if [[ -d "${CUR_DIR}/.git" ]]; then # 'git repo for dotfiles' fix: show git status only in home dir and other git repos if [[ "${CUR_DIR}" != "${HOME}" ]] || [[ "${PWD}" == "${HOME}" ]]; then # get git branch GIT_BRANCH=$($PS1_GIT_BIN symbolic-ref HEAD 2>/dev/null) if [[ ! -z $GIT_BRANCH ]]; then GIT_BRANCH=${GIT_BRANCH#refs/heads/} # get git status local GIT_STATUS=$($PS1_GIT_BIN status --porcelain 2>/dev/null) [[ -n $GIT_STATUS ]] && GIT_DIRTY=1 fi fi fi fi # build b/w prompt for git and virtual env [[ ! -z $GIT_BRANCH ]] && PS1_GIT=" (git: ${GIT_BRANCH})" [[ ! -z $VIRTUAL_ENV ]] && PS1_VENV=" (venv: ${VIRTUAL_ENV#$WORKON_HOME})" # calculate prompt length local PS1_length=$((${#USER}+${#HOSTNAME}+${#PWDNAME}+${#PS1_GIT}+${#PS1_VENV}+3)) local FILL= # if length is greater, than terminal width if [[ $PS1_length -gt $COLUMNS ]]; then # strip working directory name PWDNAME="...${PWDNAME:$(($PS1_length-$COLUMNS+3))}" else # else calculate fillsize local fillsize=$(($COLUMNS-$PS1_length)) FILL=$color_gray while [[ $fillsize -gt 0 ]]; do FILL="${FILL}─"; fillsize=$(($fillsize-1)); done FILL="${FILL}${color_off}" fi if $color_is_on; then # build git status for prompt if [[ ! -z $GIT_BRANCH ]]; then if [[ -z $GIT_DIRTY ]]; then PS1_GIT=" (git: ${color_green}${GIT_BRANCH}${color_off})" else PS1_GIT=" (git: ${color_red}${GIT_BRANCH}${color_off})" fi fi # build python venv status for prompt [[ ! -z $VIRTUAL_ENV ]] && PS1_VENV=" (venv: ${color_blue}${VIRTUAL_ENV#$WORKON_HOME}${color_off})" fi # set new color prompt PS1="${color_user}${USER}${color_off}@${color_yellow}${HOSTNAME}${color_off}:${color_white}${PWDNAME}${color_off}${PS1_GIT}${PS1_VENV} ${FILL}\n➜ " # get cursor position and add new line if we're not in first column # cool'n'dirty trick (http://stackoverflow.com/a/2575525/1164595) # XXX FIXME: this hack broke ssh =( # exec < /dev/tty # local OLDSTTY=$(stty -g) # stty raw -echo min 0 # echo -en "\033[6n" > /dev/tty && read -sdR CURPOS # stty $OLDSTTY echo -en "\033[6n" && read -sdR CURPOS [[ ${CURPOS##*;} -gt 1 ]] && echo "${color_error}↵${color_error_off}" # set title echo -ne "\033]0;${USER}@${HOSTNAME}:${PWDNAME}"; echo -ne "\007" } # set prompt command (title update and color prompt) PROMPT_COMMAND=prompt_command # set new b/w prompt (will be overwritten in 'prompt_command' later for color prompt) PS1='\u@\h:\w\$ '
      
      










All Articles