Compact bash prompt saat menggunakan pohon direktori / nama file


16

Dalam sistem dengan Ubuntu 14.04 dan bash, saya memiliki PS1variabel yang diakhiri dengan konten berikut:

\u@\h:\w\$

sehingga muncul prompt sebagai

user@machinename:/home/mydirectory$

Kadang-kadang, bagaimanapun, direktori saat ini memiliki nama panjang, atau berada di dalam direktori dengan nama panjang, sehingga muncul prompt

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

Ini akan mengisi baris di terminal dan kursor akan pergi ke baris lain, yang menjengkelkan.

Sebagai gantinya saya ingin mendapatkan sesuatu seperti

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

Apakah ada cara untuk mendefinisikan PS1variabel untuk "membungkus" dan "memadatkan" nama direktori, untuk tidak pernah melebihi jumlah karakter tertentu, memperoleh prompt yang lebih pendek?


1
Untungnya saya ingat di mana saya membaca cara mengkustomisasi prompt shell: tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html Terima kasih kepada Giles Orr, penulis Bash Prompt HOWTO dan orang-orang yang berkontribusi padanya.
stemd

Lihat juga unix.stackexchange.com/a/216871/117549 (berbasis ksh, tetapi ide serupa)
Jeff Schaller

Jawaban:


16

Pertama-tama, Anda mungkin hanya ingin mengubah \wdengan \W. Dengan begitu, hanya nama direktori saat ini yang dicetak dan bukan seluruh lintasannya:

terdon@oregano:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name $ PS1="\u@\h:\W \$ "
terdon@oregano:my_actual_directory_with_another_long_name $ 

Itu mungkin masih belum cukup jika nama direktori itu terlalu panjang. Dalam hal ini, Anda dapat menggunakan PROMPT_COMMANDvariabel untuk ini. Ini adalah variabel bash khusus yang nilainya dieksekusi sebagai perintah sebelum setiap prompt ditampilkan. Jadi, jika Anda menyetelnya ke fungsi yang menetapkan permintaan yang Anda inginkan berdasarkan pada lintasan direktori Anda saat ini, Anda bisa mendapatkan efek yang Anda cari. Misalnya, tambahkan baris ini ke ~/.bashrc:

get_PS1(){
        limit=${1:-20}
        if [[ "${#PWD}" -gt "$limit" ]]; then
                ## Take the first 5 characters of the path
                left="${PWD:0:5}"
                ## ${#PWD} is the length of $PWD. Get the last $limit
                ##  characters of $PWD.
                right="${PWD:$((${#PWD}-$limit)):${#PWD}}"
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] ${left}...${right} \$\[\033[00m\] "
        else
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] "
        fi


}
PROMPT_COMMAND=get_PS1

Efeknya terlihat seperti ini:

terdon@oregano ~ $ cd /home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name
terdon@oregano /home...th_another_long_name $ 

10

Menambahkan kembali karakter adalah solusi utama saya untuk ini

Jadi prompt saya (yang memiliki hal lain juga, membuatnya lebih lama) terlihat seperti ini:

masukkan deskripsi gambar di sini

Anda akan melihat bahwa $ akan dikembalikan sebagai baris baru

Saya mencapai ini dengan

HOST='\[\033[02;36m\]\h'; HOST=' '$HOST
TIME='\[\033[01;31m\]\t \[\033[01;32m\]'
LOCATION=' \[\033[01;34m\]`pwd | sed "s#\(/[^/]\{1,\}/[^/]\{1,\}/[^/]\{1,\}/\).*\(/[^/]\{1,\}/[^/]\{1,\}\)/\{0,1\}#\1_\2#g"`'
PS1=$TIME$USER$HOST$LOCATION'\n\$ '

Perhatikan bahwa, meskipun pada baris terpisah, pohon direktori super panjang seperti

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails disingkat menjadi

/home/durrantm/Dropbox/_/code/ruby__rails

yaitu "3 direktori teratas / _ / dua direktori terbawah" yang biasanya saya pedulikan

Ini akan memastikan bahwa garis tidak pernah menjadi terlalu panjang karena panjang pohon direktori. Jika Anda selalu menginginkan pohon direktori lengkap, sesuaikan saja LOCATION, yaitu

LOCATION=' \[\033[01;34m\]`pwd`'


1
Di mana prompt Anda sebenarnya termasuk $ ? (Lihat ini .)
G-Man Mengatakan 'Reinstate Monica'

Menambahkan \ $ di akhir, terima kasih. itu karena biasanya saya juga menunjukkan cabang git saya tapi itu terlalu banyak detail untuk di sini
Michael Durrant

1
Apa? Tidak ada baris baru? Tidak ada SGR0?
G-Man Mengatakan 'Reinstate Monica'

Menambahkan linefeed
Michael Durrant

3

Dibuat ~ / .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\$ "

Ditambahkan di ~ / .bash_profile saya:

function prompt_command {
  export PS1=$(~/.bash_prompt)
}
export PROMPT_COMMAND=prompt_command

Output adalah:

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

1

Bukan solusi untuk mempersingkat jalur yang panjang, tetapi cara yang mudah untuk mendapatkan gambaran umum yang lebih baik sambil menjaga agar semua informasi jalur tetap terlihat, menambahkan baris baru sebelum karakter terakhir. Dengan cara ini, kursor selalu dimulai di kolom yang sama, bahkan jika jalurnya cukup panjang untuk dililitkan, tetapi jendela konsol Anda harus cukup tinggi untuk tidak menggulirkan baris sebelumnya terlalu cepat. Saya menghapus kode warna untuk lebih jelas:

murphy@seasonsend:~
$ echo $PS1
\u@\h:\w\n\$
murphy@seasonsend:~
$ 

1

Saya menggunakan ini, ia membungkus ke beberapa baris dan indentasi dengan panjang user@hostsehingga mengasumsikan arus PS1secara efektif ' \u@\h:\w$'. Itu tidak memotong jalan, dan menyesuaikan dengan lebar terminal saat ini. Itu hanya membagi jalan /, sehingga tidak elegan menangani direktori yang sangat panjang (tapi itu menghemat ruang untuk seleksi / salin). Itu memastikan Anda selalu memiliki setidaknya 20 karakter ruang yang tersedia untuk input.

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

Ini berfungsi dengan mengeluarkan keajaiban \w(hanya cocok \w$untuk ini) PS1dan menggantinya $PWD, lalu membungkusnya sebagai string karakter sederhana. Ini mengkomputasi ulang PS1setiap kali dari nilai asli yang disimpan _PS1, ini berarti lolos "tak terlihat" juga dipertahankan, string prompt penuh asli saya untuk xtermdan huruf tebal:

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

Dan hasil akhirnya di terminal 80 kolom:

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$ _

Ini berfungsi dari bash-3.2 seperti printf -v varyang digunakan. Karena berbagai kompleksitas itu perlu penyesuaian untuk variasi lain PS1.

(Jalur di bilah judul xterm tidak dibungkus atau disingkat, sesuatu yang bisa dilakukan dengan memasukkan salah satu jawaban lain di sini ke dalam fungsi di atas.)


0

Sebagai alternatif, di .zshrc saya menyingkat huruf pertama dari setiap direktori jika lebar piksel melebihi lebar tertentu:

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

menjadi:

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

Inilah fungsi zsh untuk melakukannya:

     # 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

Saya benar-benar menggunakan ini untuk memperbarui judul terminal sehingga dengan banyak tab, saya bisa tetap tab mana. .Zshrc lengkap untuk melakukan ini ada di sini .

Ini sangat berguna karena menjaga konteks dan di zsh memungkinkan Anda untuk dengan cepat menabrak direktori dalam format yang sama. (mis. mengetik cd /h/m/s/<tab>akan otomatis terisi ke cd /home/mydirectory1/second_directory)


Bagaimana ini berlaku untuk pertanyaan yang diajukan OP, tentang bagaimana cara menentukan prompt PS1?
Anthon

Diedit untuk kejelasan, $ t menjadi PS1
Richard

0

Coba gunakan skrip Python ini . Itu memotong bagian individu dari nama path, persis seperti yang Anda inginkan dalam pertanyaan Anda. Ia juga menggunakan elipsis unicode yang hanya memakan satu kolom, bukan tiga.

Contoh output untuk jalur Anda (ketika diberi batas 30 karakter):

/home/mydir…/second…/my_actua

Perlu dicatat bahwa solusi ini menangani Unicode dengan benar dalam nama direktori dengan menggunakan wcswidth. ${#PWD}, yang jawaban lain telah gunakan, akan salah menilai lebar visual dari setiap jalur yang berisi karakter UTF-8.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.