กระชับ bash พรอมต์เมื่อใช้ต้นไม้ไดเรกทอรี / ชื่อไฟล์


16

ในระบบที่มี 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ตัวแปรเพื่อ "ห่อ" และ "กระชับ" ชื่อไดเรกทอรีเพื่อไม่เกินจำนวนอักขระที่กำหนดรับพรอมต์ที่สั้นลงหรือไม่


1
โชคดีที่ฉันจำตำแหน่งที่ฉันอ่านวิธีปรับแต่ง shell prompt: tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.htmlขอบคุณไปที่ Giles Orr ผู้เขียน Bash Prompt HOWTO และผู้ที่สนับสนุน
stemd

ดูเพิ่มเติมที่unix.stackexchange.com/a/216871/117549 (อิงจาก ksh แต่เป็นความคิดที่คล้ายกัน)
Jeff Schaller

คำตอบ:


16

แรกของทั้งหมดที่คุณก็อาจต้องการที่จะเปลี่ยนด้วย\w \Wด้วยวิธีนี้เฉพาะชื่อของไดเรกทอรีปัจจุบันเท่านั้นที่พิมพ์และไม่ใช่เส้นทางทั้งหมด:

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 $ 

นั่นอาจยังไม่เพียงพอหากชื่อไดเรกทอรียาวเกินไป ในกรณีนี้คุณสามารถใช้PROMPT_COMMANDตัวแปรสำหรับสิ่งนี้ นี่เป็นตัวแปร bash พิเศษที่มีค่าถูกเรียกใช้งานเป็นคำสั่งก่อนที่จะแสดงพรอมต์แต่ละครั้ง ดังนั้นหากคุณตั้งค่านั้นเป็นฟังก์ชันที่ตั้งค่าพรอมต์ที่คุณต้องการตามความยาวของเส้นทางไดเรกทอรีปัจจุบันของคุณคุณจะได้รับผลกระทบที่ตามมา ตัวอย่างเช่นเพิ่มบรรทัดเหล่านี้ใน~/.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

ผลที่ได้จะเป็นดังนี้:

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

การเพิ่มการส่งคืนอักขระเป็นโซลูชันหลักของฉันสำหรับสิ่งนี้

ดังนั้นข้อความแจ้งของฉัน (ซึ่งมีเนื้อหาอื่นด้วยทำให้ยาวขึ้น) ดูเหมือนว่า:

ป้อนคำอธิบายรูปภาพที่นี่

คุณจะสังเกตเห็นว่า $ ได้รับผลตอบแทนเป็นบรรทัดใหม่

ฉันบรรลุสิ่งนี้ด้วย

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\$ '

โปรดทราบว่าแม้ว่าจะอยู่ในบรรทัดแยกต่างหากต้นไม้ไดเรกทอรีที่ยาวมากเช่น

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails สั้นลงไป

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

นั่นคือ "ไดเรกทอรี 3 อันดับแรก / _ / สองไดเรกทอรีด้านล่าง" ซึ่งมักเป็นสิ่งที่ฉันสนใจ

สิ่งนี้จะทำให้แน่ใจได้ว่าบรรทัดจะไม่ยาวเกินไปเนื่องจากความยาวแผนผังไดเรกทอรี หากคุณต้องการโครงสร้างไดเรกทอรีเต็มรูปแบบเพียงแค่ปรับ LOCATION เช่น

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

ข้อมูลเพิ่มเติมเกี่ยวกับสีที่unix.stackexchange.com/q/124407/10043
Michael Durrant

1
พรอมต์ของคุณรวมอยู่$ ที่ไหน (ดูสิ่งนี้ )
G-Man กล่าวว่า 'Reinstate Monica'

เพิ่ม \ $ ในตอนท้ายขอบคุณ เป็นเพราะปกติแล้วฉันก็แสดงสาขา git ของฉันด้วย แต่นั่นเป็นรายละเอียดที่มากเกินไปสำหรับที่นี่
Michael Durrant

1
อะไร? ไม่มีการขึ้นบรรทัดใหม่หรือ ไม่มี SGR0
G-Man กล่าวว่า 'Reinstate Monica'

เพิ่ม linefeed
Michael Durrant

3

สร้าง ~ / .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$

1

ไม่ใช่วิธีที่จะทำให้เส้นทางที่สั้นลงสั้นลง แต่เป็นวิธีที่สะดวกในการรับภาพรวมที่ดีขึ้นในขณะที่ทำให้ข้อมูลเส้นทางทั้งหมดมองเห็นได้คือการเพิ่มบรรทัดใหม่ก่อนอักขระตัวสุดท้าย วิธีนี้เคอร์เซอร์จะเริ่มต้นเสมอในคอลัมน์เดียวกันแม้ว่าเส้นทางจะยาวพอที่จะล้อมรอบ แต่หน้าต่างคอนโซลของคุณควรสูงพอที่จะไม่เลื่อนออกจากบรรทัดก่อนหน้านี้เร็วเกินไป ฉันลบรหัสสีเพื่อความชัดเจนมากขึ้น:

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

1

ฉันใช้สิ่งนี้มันล้อมรอบหลายบรรทัดและเยื้องตามความยาว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ซึ่งหมายความว่า Escape "ล่องหน" ถูกเก็บรักษาไว้เช่นกันสตริงข้อความต้นฉบับเต็มของฉันสำหรับ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$ _

ใช้งานได้จาก bash-3.2 ตามที่printf -v varใช้ เนื่องจากความซับซ้อนต่าง ๆก็จะต้องปรับบางอย่างสำหรับรูปแบบอื่น ๆ PS1ของ

(เส้นทางในแถบชื่อxtermไม่ได้เป็นแบบพันหรือตัวย่อสิ่งที่สามารถทำได้โดยการรวมคำตอบอย่างใดอย่างหนึ่งที่นี่ลงในฟังก์ชั่นด้านบน)


0

อีกทางเลือกหนึ่งใน. 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 เต็มรูปแบบที่จะทำคือที่นี่

สิ่งนี้มีประโยชน์มากเนื่องจากเก็บบริบทและใน zsh ช่วยให้คุณสามารถแท็บไดเรกทอรีในรูปแบบเดียวกันได้อย่างรวดเร็ว (เช่นการพิมพ์cd /h/m/s/<tab>จะเติมข้อความอัตโนมัติให้cd /home/mydirectory1/second_directory)


สิ่งนี้นำไปใช้กับคำถามที่ OP ถูกโพสต์เกี่ยวกับวิธีการกำหนดพรอมต์ PS1 ได้อย่างไร
Anthon

แก้ไขเพื่อความกระจ่างแล้ว $ t กลายเป็น PS1
Richard

0

ลองใช้สคริปต์ Pythonนี้ มันตัดส่วนของชื่อพา ธ แต่ละส่วนเหมือนกับที่คุณต้องการในคำถามของคุณ นอกจากนี้ยังใช้จุดไข่ปลา Unicode ที่ใช้เพียงหนึ่งคอลัมน์แทนสาม

ตัวอย่างเอาต์พุตสำหรับพา ธ ของคุณ (เมื่อกำหนดขีด จำกัด 30 ตัวอักษร):

/home/mydir…/second…/my_actua

มันเป็นที่น่าสังเกตว่าการแก้ปัญหานี้ได้อย่างถูกต้องจัดการ Unicode wcswidthในชื่อไดเรกทอรีโดยใช้ ${#PWD}ซึ่งมีคำตอบอื่นที่ใช้งานอยู่จะตัดสินความกว้างของเส้นทางที่มีอักขระ UTF-8 อย่างไม่เหมาะสม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.