web-dev-qa-db-ja.com

ディレクトリツリー/ファイル名を使用する場合のコンパクトbashプロンプト

Ubuntu 14.04とbashのシステムでは、次の内容で終わるPS1変数があります。

\u@\h:\w\$

プロンプトが次のように表示されるようにします

user@machinename:/home/mydirectory$

ただし、現在のディレクトリが長い名前である場合や、現在のディレクトリが長い名前のディレクトリ内にある場合があるため、プロンプトは次のようになります。

user@machinename:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name$

これはターミナルの行を埋め、カーソルは別の行に移動します。これは面倒です。

代わりに次のようなものを入手したい

user@machinename:/home/mydirectory1/...another_long_name$

PS1変数を定義して、特定の文字数を超えないようにディレクトリ名を「ラップ」および「圧縮」して、より短いプロンプトを取得する方法はありますか?

16
BowPark

作成された〜/ .bash_Prompt:

maxlen=36
# set leftlen to zero for printing just the right part of the path
leftlen=19
shortened="..."
# Default PWD
nPWD=${PWD}
if [ ${#nPWD} -gt $maxlen ]; then
  offset=$(( ${#nPWD} - $maxlen + $leftlen ))
  nPWD="${nPWD:0:$leftlen}${shortened}${nPWD:$offset:$maxlen}"
else
  nPWD='\w'
fi
echo "\u@\h:$nPWD\$ "

〜/ .bash_profileに追加:

function Prompt_command {
  export PS1=$(~/.bash_Prompt)
}
export Prompt_COMMAND=Prompt_command

出力は次のとおりです。

user@machinename:/home/mydirectory1/...another_long_name$
3
hellcode

私はこれを使用し、複数行に折り返してuser@Hostの長さだけインデントするため、現在のPS1は事実上 '\u@\h:\w$'であると想定しています。パスは切り捨てられず、現在の端子幅に適応します。 /でパスを分割するだけなので、本当に長いディレクトリをエレガントに処理しません(ただし、選択/コピーのためのスペースは保持します)。これにより、常に少なくとも20文字のスペースが入力可能になります。

readonly _PS1="${PS1}" 2>/dev/null

function myprompt()
{
    local IFS
    local nn nb pbits xpwd="" ww=60 len=0 pp='\\w\$ '
    local indent uh="${LOGNAME}@${HOSTNAME//.*/}"

    test -n "$COLUMNS" && let ww=$COLUMNS-20  # may be unset at startup

    PS1="${_PS1}"
    if [ ${#PWD} -ge $ww ]; then
        printf -v indent "%${#uh}s%s" " " "> "  # indent strlen(user@Host)

        IFS=/ pbits=( $PWD ); unset IFS
        nb=${#pbits[*]}
        for ((nn=1; nn<nb; nn++)) {
            if [ $(( $len + 1 + ${#pbits[$nn]} )) -gt $ww ]; then
                xpwd="${xpwd}/...\n${indent}..."
                len=0
            fi
            xpwd="${xpwd}/${pbits[$nn]}"
            let len=len+1+${#pbits[$nn]}
        }
        # add another newline+indent if the input space is too tight
        if (( ( ${#uh} + len ) > ww )); then
            printf -v xpwd "${xpwd}\n%${#uh}s" " " 
        fi 
        PS1="${PS1/$pp/$xpwd}$ "    
    fi
}
Prompt_COMMAND=myprompt

これは、\wからマジック\w$(この場合はPS1のみに一致)を取得して$PWDに置き換え、プレーンな文字列としてラップすることで機能します。 PS1に保存されている元の値から_PS1を毎回再計算します。これは、「不可視」のエスケープも保持されることを意味します。xtermの元の完全なプロンプト文字列と太字のプロンプト:

PS1="\[\033]0;\u@\h:\w\007\]\[$(tput bold)\]\u@\h\[$(tput sgr0)\]:\w$ "

そして、最終的な結果は80列のターミナルになります。

mr@onomatopoeia:~$ cd /usr/src/linux/tools/perf/scripts/Perl/Perf-Trace-Util/lib/Perf/Trace
mr@onomatopoeia:/usr/src/linux/tools/perf/scripts/Perl/Perf-Trace-Util/lib/...
               > .../Perf/Trace$ _

printf -v varが使用されるため、これはbash-3.2から機能します。 さまざまな複雑さ のため、PS1の他のバリエーションには調整が必要です。

xtermタイトルバーのパスは折り返されたり省略されたりしません。これは、他の回答の1つを上記の関数に組み込むことで実行できます。 )

1
mr.spuratic

this Python script を使用してみてください。これは、質問で希望したとおりに、パス名の個々のセクションを切り取ります。また、Unicodeの省略記号を使用して、 3列ではなく1列のみ。

パスの出力例(30文字の制限が指定されている場合):

/home/mydir…/second…/my_actua…

このソリューションは wcswidth を使用してディレクトリ名のUnicodeを正しく処理することに注意してください。 ${#PWD}は他の回答で使用されていますが、UTF-8文字を含むパスの視覚的な幅を誤って判断します。

0
Functino

別の方法として、私の.zshrcでは、ピクセル幅が特定の幅を超えている場合は、各ディレクトリの最初の文字に省略します。

user@machinename:/home/mydirectory1/second_directory
user@machinename:/home/mydirectory1/second_directory/my_actual_directory

になる:

user@machinename:/h/mydirectory1/second_directory
user@machinename:/h/m/s/my_actual_directory

これを行うzsh関数は次のとおりです。

     # get the path
     t=`print -P "%m:%~"`;
     t=`echo $t | sed -r 's/([^:])[^:]*([0-9][0-9]):|([^:])[^:]*([^:]):/\1\2\3\4:/'`;
     oldlen=-1;

     # create 4 buckets of letters by their widths
     t1="${t//[^ijlIFT]}";
     t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
     t3="${t//[^ABEKPSVXYCDHNRUw]}";
     t4="${t//[^GoQMmW]}";

     # keep abbreviating parent directories in the path until under 456 pixels
     while (( ( ( ${#t1} * 150 ) + ( ${#t2} * 178 ) + ( ${#t3} * 190 ) + ( ${#t4} * 201 ) ) > 4560 && ${#t}!=oldlen)) {
       oldlen=${#t};
       t=`echo $t | sed 's/\/\(.\)[^\/][^\/]*\//\/\1\//'`;
       t1="${t//[^ijlIFT]}";
       t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
       t3="${t//[^ABEKPSVXYCDHNRUw]}";
       t4="${t//[^GoQMmW]}";
     };

     PS1=$t

これを実際に使用してターミナルのタイトルを更新し、複数のタブがある場合、どのタブがどのタブであるかをまっすぐに保つことができます。これを行う完全な.zshrcは here です。

これはコンテキストを保持し、zshでは同じ形式のディレクトリをすばやくタブで補完できるため、非常に便利です。 (たとえば、cd /h/m/s/<tab>と入力すると、cd /home/mydirectory1/second_directoryにオートコンプリートされます)

0
Richard