Để có được đầu ra giống như bạn lưu ý trong câu hỏi của bạn, tất cả những gì cần thiết là:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Bạn không cần phải vặn vẹo. Hai dòng này sẽ làm tất cả trong bất kỳ shell nào giả vờ bất cứ thứ gì gần với khả năng tương thích POSIX.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Nhưng tôi thích điều này. Và tôi muốn chứng minh các nguyên tắc cơ bản của những gì làm cho công việc này tốt hơn một chút. Vì vậy, tôi chỉnh sửa điều này một chút. Bây giờ tôi đã nhét nó vào /tmp
nhưng tôi nghĩ tôi cũng sẽ giữ nó cho riêng mình. Nó ở đây:
cat /tmp/prompt
KHUYẾN MÃI:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Lưu ý: gần đây đã biết về yash , tôi đã xây dựng nó ngày hôm qua. Vì bất kỳ lý do gì, nó không in byte đầu tiên của mọi đối số với %c
chuỗi - mặc dù các tài liệu cụ thể về các phần mở rộng char cho định dạng đó và vì vậy nó có thể liên quan - nhưng nó chỉ tốt với%.1s
Đó là toàn bộ. Có hai điều chính đang diễn ra ở đó. Và đây là những gì nó trông giống như:
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 >
PARSING $PWD
Mỗi lần $PS1
được đánh giá, nó phân tích cú pháp và in $PWD
để thêm vào dấu nhắc. Nhưng tôi không thích toàn bộ $PWD
màn hình của mình, vì vậy tôi chỉ muốn chữ cái đầu tiên của mỗi mẩu bánh mì trong đường dẫn hiện tại xuống thư mục hiện tại mà tôi muốn xem đầy đủ. Như thế này:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Có một vài bước ở đây:
IFS=/
chúng ta sẽ phải phân chia hiện tại $PWD
và cách đáng tin cậy nhất để làm điều đó là $IFS
chia tách /
. Không cần phải bận tâm với nó sau đó - tất cả việc phân tách từ đây trở đi sẽ được xác định bởi $@
mảng tham số vị trí của shell trong lệnh tiếp theo như:
set -- ${PWD%"${last=${PWD##/*/}}"}
Vì vậy, cái này là một chút khó khăn, nhưng điều chủ yếu là chúng ta tách đang $PWD
trên /
các biểu tượng. Tôi cũng sử dụng mở rộng tham số để gán cho $last
mọi thứ sau khi bất kỳ giá trị nào xảy ra giữa /
dấu gạch chéo trái và phải nhất . Bằng cách này, tôi biết rằng nếu tôi chỉ ở /
và chỉ có một /
thì $last
sẽ vẫn bằng nhau $PWD
và $1
sẽ trống rỗng. Vấn đề này Tôi cũng thoát $last
khỏi đầu đuôi $PWD
trước khi gán nó cho $@
.
printf "${1+%c/}" "$@"
Vì vậy, ở đây - miễn là ${1+is set}
chúng tôi printf
là %c
kẻ gây rối đầu tiên cho mỗi đối số của shell - mà chúng ta vừa đặt cho mỗi thư mục trong hiện tại $PWD
- trừ thư mục trên cùng - tách ra /
. Vì vậy, về cơ bản chúng tôi chỉ in ký tự đầu tiên của mọi thư mục trong $PWD
nhưng thư mục trên cùng. Mặc dù điều quan trọng là nhận ra điều này chỉ xảy ra nếu $1
được đặt ở tất cả, điều này sẽ không xảy ra ở gốc /
hoặc tại một lần bị xóa khỏi /
như trong /etc
.
printf "$last > "
$last
là biến tôi vừa gán cho thư mục hàng đầu của chúng tôi. Vì vậy, bây giờ đây là thư mục hàng đầu của chúng tôi. Nó in ra hay không tuyên bố cuối cùng đã làm. Và nó cần một chút gọn gàng >
cho các biện pháp tốt.
NHƯNG GÌ VỀ SỰ TĂNG CƯỜNG?
Và sau đó là vấn đề của $PS2
điều kiện. Tôi đã chỉ ra trước đây làm thế nào điều này có thể được thực hiện mà bạn vẫn có thể tìm thấy bên dưới - đây về cơ bản là một vấn đề về phạm vi. Nhưng có thêm một chút nữa trừ khi bạn muốn bắt đầu thực hiện một loạt các không printf \b
gian và sau đó cố gắng cân bằng số lượng nhân vật của họ ... ugh. Vì vậy, tôi làm điều này:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Một lần nữa, ${parameter##expansion}
tiết kiệm trong ngày. Mặc dù có một điều lạ ở đây - chúng tôi thực sự đã đặt biến trong khi chúng tôi tự loại bỏ biến đó. Chúng tôi sử dụng giá trị mới của nó - đặt dải giữa - như toàn cầu mà chúng tôi tách. Bạn thấy sao? Chúng tôi ##*
tách tất cả từ phần đầu của biến tăng dần sang ký tự cuối cùng có thể là bất cứ thứ gì từ đó [$((PS2c=0))-9]
. Chúng tôi đảm bảo theo cách này không tạo ra giá trị, nhưng chúng tôi vẫn chỉ định nó. Nó thật tuyệt - Tôi chưa bao giờ làm điều đó trước đây. Nhưng POSIX cũng đảm bảo với chúng tôi rằng đây là cách di động nhất có thể được thực hiện.
Và đó là nhờ POSIX quy định ${parameter} $((expansion))
giữ các định nghĩa này trong vỏ hiện tại mà không yêu cầu chúng tôi đặt chúng trong một khung con riêng biệt, bất kể chúng tôi đánh giá chúng ở đâu. Và đây là lý do tại sao nó hoạt động trong dash
và sh
cũng như nó làm trong bash
và zsh
. Chúng tôi không sử dụng thoát thoát phụ thuộc shell / terminal và chúng tôi để các biến tự kiểm tra. Đó là những gì làm cho mã di động nhanh chóng.
Phần còn lại khá đơn giản - chỉ cần tăng bộ đếm của chúng tôi cho mỗi lần $PS2
được đánh giá cho đến khi $PS1
một lần nữa đặt lại nó. Như thế này:
PS2='$((PS2c=PS2c+1)) > '
Vì vậy, bây giờ tôi có thể:
DASH DEMO
ENV=/tmp/prompt dash -i
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 > printf '\t%s\n' "$PS1" "$PS2" "$PS2c"
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
0
/u/s/m/man3 > cd ~
/h/mikeserv >
SH DEMO
Nó hoạt động tương tự trong bash
hoặc sh
:
ENV=/tmp/prompt sh -i
/h/mikeserv > cat <<HEREDOC
1 > $( echo $PS2c )
2 > $( echo $PS1 )
3 > $( echo $PS2 )
4 > HEREDOC
4
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
/h/mikeserv > echo $PS2c ; cd /
0
/ > cd /usr/share
/u/share > cd ~
/h/mikeserv > exit
Như tôi đã nói ở trên, vấn đề chính là bạn cần xem xét nơi bạn thực hiện tính toán của mình. Bạn không nhận được trạng thái trong vỏ cha mẹ - vì vậy bạn không tính toán ở đó. Bạn có trạng thái trong subshell - vì vậy đó là nơi bạn tính toán. Nhưng bạn làm định nghĩa trong vỏ cha.
ENV=/dev/fd/3 sh -i 3<<\PROMPT
ps1() { printf '$((PS2c=0)) > ' ; }
ps2() { printf '$((PS2c=PS2c+1)) > ' ; }
PS1=$(ps1)
PS2=$(ps2)
PROMPT
0 > cat <<MULTI_LINE
1 > $(echo this will be line 1)
2 > $(echo and this line 2)
3 > $(echo here is line 3)
4 > MULTI_LINE
this will be line 1
and this line 2
here is line 3
0 >
man 1 mktemp
.