Câu hỏi Bash nhắc: làm thế nào để có các chữ cái đầu của đường dẫn thư mục


Tôi thường chỉ có tên của thư mục hiện tại trong dấu nhắc bash của tôi (PS1='\u@\h:\W$ '), vì vậy nếu tôi ở ~/projects/superapp/src/ Tôi có:

hamish@host:src$ 

Tuy nhiên tôi muốn có một dấu hiệu của con đường đầy đủ mà không có con đường đầy đủ. Tôi đã nhìn thấy ảnh chụp màn hình nơi mọi người sẽ có

hamish@host:~/p/s/src$ 

nếu trong thư mục ví dụ trên. Vậy giá trị của PS1 sẽ mang lại điều gì? Hoặc thất bại, tôi cần những kịch bản gì trong .bashrc để sản xuất?


4
2017-08-24 21:34


gốc


Đây là một câu hỏi hay, nhưng nó cũng là một bản sao chính xác của một câu hỏi (đã được trả lời) trên Stack Overflow: stackoverflow.com/questions/1616678/bash-pwd-shortening - Telemachus
Nó không thực sự là một bản sao chính xác, mặc dù nó là tương tự. Nhưng nhìn qua đó tôi không thể dễ dàng nhìn thấy chính xác làm thế nào để làm những gì tôi muốn - mà không phải là chiều dài cố định, nhưng chỉ tắt. Tôi có thể đi và đăng câu trả lời ở đây nếu tôi thành công. - Hamish Downer
Đủ công bằng. Tôi đã đăng câu trả lời bên dưới, dựa trên chuỗi đó. - Telemachus
Nó cũng là một bản sao của cái này. - Dennis Williamson
@ Telemachus - nó là tốt để tham khảo một giải pháp từ một trang web khác, nhưng không có lý do một câu hỏi không thể tồn tại trên cả hai trang web, nếu đó là chủ đề trên cả hai. Câu hỏi này là chủ đề về siêu người dùng, nó có thể và nên được trả lời ở đây. - Gnoupi


Các câu trả lời:


Ok, tôi đã tò mò, vì vậy đây là một giải pháp:

  1. Đầu tiên, tạo một hàm bằng cách sử dụng một chút tinh chỉnh Câu trả lời của William Pursell đến SO câu hỏi Tôi liên kết trong bình luận của tôi ở trên.
  2. Tiếp theo, đặt giá trị đó vào $ PS1 của bạn \$(function_name) ở nơi thích hợp.

Ví dụ:

short_pwd() {
    cwd=$(pwd | perl -F/ -ane 'print join( "/", map { $i++ < @F - 1 ?  substr $_,0,1 : $_ } @F)')
    echo -n $cwd
}
# later in your .bashrc
PS1="\u \$(short_pwd) \$ "

Tôi hy vọng rằng ai đó có kỹ năng hơn trong Bash-scripting hơn tôi có thể đề xuất các cách để làm sạch hàm, nhưng điều này sẽ cho bạn một số ý tưởng về cách sử dụng đầu ra của một lệnh khác (hoặc hàm Bash) trong dấu nhắc. Xem thêm tại đây: http://www.linux.org/docs/ldp/howto/Bash-Prompt-HOWTO/x279.html

Dựa trên nhận xét của bạn, tôi nhìn lại và nhận ra rằng giải pháp của tôi cần phải được trích dẫn kép. Nếu bạn trích dẫn một hàm như vậy, thì nó sẽ không hoạt động chút nào.


2
2017-08-24 22:13



Tôi không biết perl nên không thể đánh giá giải pháp chung, nhưng tôi nghĩ bạn sẽ phải chỉnh sửa nó để sử dụng PROMPT_COMMAND như trong giải pháp của tôi, nếu không PS1 sẽ được đặt khi bạn bắt đầu bash và sẽ không thay đổi khi bạn thay đổi thư mục. - Hamish Downer
@ Hamish Không, không đúng. Điều này thay đổi khi bạn cd. Tôi đang sử dụng nó ngay bây giờ. (Và đó không phải là một điều Perl. Nó có liên quan đến cách thức hoạt động của PS1. Bạn có thể có thông tin động trong đó trong một hàm thông qua \$(function). - Telemachus
@ Hamish Nhưng bạn đã giúp tôi thấy rằng tôi cần báo giá gấp đôi, không đơn như tôi đã viết ban đầu. Lời nhắc tôi đang thử nghiệm ở đây liên quan đến việc thoát màu và phức tạp hơn, và tôi vô tình đơn giản hóa nó bằng cách sử dụng dấu nháy đơn. Lấy làm tiếc. - Telemachus
ah thú vị, tôi rõ ràng là cần phải tìm hiểu thêm một chút về bash ... - Hamish Downer


Tôi thích cách tiếp cận của meowsqueak, cố gắng để ở trong bash cho hiệu suất. Nhưng tôi muốn con đường của tôi để viết tắt tên thư mục dài xuống một char.

me@comp:~ $ cd my/path/haslongnames/
me@comp:~my/p/h $

Điều này dựa trên giải pháp của meowsqueak. Nó có thể đứng một số cải tiến / nhiều tính năng hơn nhưng nó giải quyết vấn đề cơ bản mà không bắn lên sed.

Đây là một tập tin thực thi, ví dụ ~ / bin / ps1

# set this to whatever you want:
MAX_PWD_LENGTH=30
function shorten_pwd
{
    # This function ensures that the PWD string does not exceed $MAX_PWD_LENGTH characters
    PWD=$(pwd)

    # determine part of path within HOME, or entire path if not in HOME
    RESIDUAL=${PWD#$HOME}

    # compare RESIDUAL with PWD to determine whether we are in HOME or not
    if [ X"$RESIDUAL" != X"$PWD" ]
    then
        PREFIX="~"
    fi

    # check if residual path needs truncating to keep total length below MAX_PWD_LENGTH
    NORMAL=${PREFIX}${RESIDUAL}
    if [ ${#NORMAL} -ge $(($MAX_PWD_LENGTH)) ]
    then
        newPWD=${PREFIX}
        OIFS=$IFS
        IFS='/'
        bits=$RESIDUAL
        for x in $bits
        do
            if [ ${#x} -ge 3 ]
            then
                NEXT="/${x:0:1}"
            else
                NEXT="$x"
            fi
            newPWD="$newPWD$NEXT"
        done

        IFS=$OIFS
    else
        newPWD=${PREFIX}${RESIDUAL}
    fi

    # return to caller
    echo $newPWD
}
export PS1="\u@\h:$(shorten_pwd) $ "

Trong .bash_profile của tôi, tôi có

PROMPT_COMMAND="source $HOME/bin/ps1"

3
2017-08-03 17:01



Bạn có thể vui lòng giải thích cách chức năng không khiếu nại trên dòng: RESIDUAL=${PWD#$HOME}  ngay cả cú pháp highlighter cũng nói rằng nó rất sôi nổi với # comment - stagl
Trung thực @stagl, nó đã được nhiều năm kể từ khi tôi đã sử dụng dấu nhắc này. Tôi không nhớ nhiều về lý do tại sao bất kỳ điều này hoạt động. : / - leff
Phụ lục. Chỉ tìm thấy điều này trong khi nghiên cứu những thứ khác. gnu.org/software/bash/manual/html_node/…  Nếu từ đó khớp với giá trị mở rộng của tham số, thì kết quả của việc mở rộng là giá trị mở rộng của tham số với mẫu phù hợp ngắn nhất (trường hợp)" - leff


Tôi viết lại điều này gần đây, dựa trên một kịch bản khác tôi đã viết cách đây nhiều năm - đây là một trong những tối ưu hóa để chạy bên trong bash càng nhiều càng tốt, để tránh dĩa tốn kém. Đó là gần như 8x nhanh hơn chức năng cũ của tôi sử dụng awk / sed.

Nó tạo ra kết quả tốt đẹp. Nó giữ phần pwd của dấu nhắc không quá MAX_PWD_LENGTH ký tự, và nếu bạn đang ở trong một subdir của $ HOME, nó cũng làm cho nó rõ ràng:

Ví dụ:

pc770-ubu:~ $ cd ~/a/b/c
pc770-ubu:~/a/b/c $ cd d/e/f
pc770-ubu:~/a/b/c/d/e/f $ cd g
pc770-ubu:~/a/b/c/d/e/f/g $ cd h
pc770-ubu:~/a/b/c/d/e/f/g/h $ cd i
pc770-ubu:~/a/b/c/d/e/f/g/h/i $ cd j
pc770-ubu:~/a/b/c/d/e/f/g/h/i/j $ cd k
pc770-ubu:~/a/b/c/d/e/f/g/h/i/j/k $ cd l
pc770-ubu:~../c/d/e/f/g/h/i/j/k/l $ cd m
pc770-ubu:~../d/e/f/g/h/i/j/k/l/m $ cd n
pc770-ubu:~../e/f/g/h/i/j/k/l/m/n $ cd o
pc770-ubu:~../f/g/h/i/j/k/l/m/n/o $ cd /tmp/a/b/c/d/e/f
pc770-ubu:/tmp/a/b/c/d/e/f $ cd g
pc770-ubu:/tmp/a/b/c/d/e/f/g $ cd h
pc770-ubu:/tmp/a/b/c/d/e/f/g/h $ cd i
pc770-ubu:/tmp/a/b/c/d/e/f/g/h/i $ cd j
pc770-ubu:/../a/b/c/d/e/f/g/h/i/j $ cd k
pc770-ubu:/../b/c/d/e/f/g/h/i/j/k $ cd l
pc770-ubu:/../c/d/e/f/g/h/i/j/k/l $ cd m
pc770-ubu:/../d/e/f/g/h/i/j/k/l/m $ cd
pc770-ubu:~ $ 

Hàm bash (gọi hàm này khi xây dựng biến PS1 của bạn):

# set this to whatever you want:
MAX_PWD_LENGTH=20

function shorten_pwd
{
    # This function ensures that the PWD string does not exceed $MAX_PWD_LENGTH characters
    PWD=$(pwd)

    # if truncated, replace truncated part with this string:
    REPLACE="/.."

    # determine part of path within HOME, or entire path if not in HOME
    RESIDUAL=${PWD#$HOME}

    # compare RESIDUAL with PWD to determine whether we are in HOME or not
    if [ X"$RESIDUAL" != X"$PWD" ]
    then
        PREFIX="~"
    fi

    # check if residual path needs truncating to keep total length below MAX_PWD_LENGTH
    # compensate for replacement string.
    TRUNC_LENGTH=$(($MAX_PWD_LENGTH - ${#PREFIX} - ${#REPLACE} - 1))
    NORMAL=${PREFIX}${RESIDUAL}
    if [ ${#NORMAL} -ge $(($MAX_PWD_LENGTH)) ]
    then
        newPWD=${PREFIX}${REPLACE}${RESIDUAL:((${#RESIDUAL} - $TRUNC_LENGTH)):$TRUNC_LENGTH}
    else
        newPWD=${PREFIX}${RESIDUAL}
    fi

    # return to caller
    echo $newPWD
}

EDIT: lỗi cố định với độ dài chuỗi tuyệt đối


2
2017-08-25 02:27





PROMPT_DIRTRIM=3

sẽ buộc \ w mở rộng tới tối đa ba phần tử đường dẫn của đường dẫn thư mục làm việc hiện tại, với phần trước, nếu có, được thay thế bằng "...".


2
2018-04-16 14:28





Chỉ cần thêm nội dung này (và chỉnh sửa theo ý bạn) cho .bashrc:

PS1='\u@\h:`pwd | sed -e "s/\/\(.\)[^\/]\+/\/\1/g"`\$ '

1
2017-08-24 22:29



Tôi đã thử điều đó, nhưng tiếc là nó đặt giá trị của PS1 một lần khi bạn bắt đầu bash và sẽ không cập nhật nó sau đó. Vì vậy, bạn sẽ thay đổi thư mục và lời nhắc của bạn sẽ không thay đổi - tôi đã mắc lỗi này và sau đó đã chơi và phải gãi đầu để giải quyết nó. Xem câu trả lời (đã chỉnh sửa) của tôi để biết cách sử dụng PROMPT_COMMAND - Hamish Downer
Không, nó làm việc cho tôi, nó thay đổi mọi lúc. - cYrus
Và echo $PS1 cho: \ u @ \ h: 'pwd | sed -e "s / \ / (.) [^ \ /] \ + / \ / \ 1 / g" '\ $ để mã không được mã hóa cứng vào biến (tôi không biết cách ghi đè đánh dấu này, chỉ thay thế 'bằng `). - cYrus
ồ được thôi. Tôi sẽ đọc thêm một chút nữa, cảm ơn vì đã giải thích. - Hamish Downer


Tôi đã làm một chút googling trong thời gian chờ đợi, và sau khi đi qua một vài thuật ngữ tìm kiếm, tôi đã đi qua bài viết này đề cập đến vỏ cá làm những gì tôi muốn và cung cấp một cách để làm điều đó. Tôi đã sửa đổi nó để người dùng và máy chủ lưu trữ cũng được hiển thị và kết thúc với sự súc tích hợp lý:

# abbreviate the dir path
PROMPT_COMMAND='CurDir=`pwd|sed -e "s!$HOME!~!"|sed -re "s!([^/])[^/]+/!\1/!g"`'
PS1="\u@\h:\$CurDir \$ "

Về cơ bản mỗi lần lời nhắc sắp được hiển thị, PROMPT_COMMAND sẽ đặt $CurDir vào đường dẫn thư mục được viết tắt mà sau đó được sử dụng trong $PS1. Hãy nhớ rằng nếu PROMPT_COMMAND được đặt ở nơi khác, bạn sẽ cần phải thêm lệnh trên vào cuối của lệnh đó, trước bởi ;. Vì vậy, đối với ví dụ phổ biến về đặt tiêu đề của xterm bạn sẽ kết thúc với

PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD/$HOME/~}\007"; CurDir=`pwd|sed -e "s!$HOME!~!"|sed -re "s!([^/])[^/]+/!\1/!g"`'

Một số cách khác có thể để viết tắt đường dẫn có thể được tìm thấy:


1
2017-08-24 22:38





Một phiên bản khác của @Telemachus short_pwd (), không có yêu cầu perl.

short_pwd() {
cwd=$(pwd)

if [ $cwd == $HOME ]; then echo -n "~"; return; fi 
if [ $cwd == "/" ]; then echo -n "/"; fi 

for l in $(echo $cwd | tr "/" "\n"); do 
    echo -n "/"
    echo -n ${l:0:1}
done
echo -n ${l:1}
}

1
2017-09-13 20:05