Dấu nhắc PS1 để hiển thị thời gian đã trôi qua


10

Tôi hiện đang sử dụng điều này để hiển thị thời gian hiện tại trong dấu nhắc bash của mình:

PS1=\[\e[0;32m\]\t \W>\[\e[1;37m\]

20:42:23 ~>

Có thể hiển thị thời gian đã trôi qua kể từ lời nhắc trước đó không? Nhu la:

00:00:00 ~> sleep 10
00:00:10 ~> sleep 20
00:00:20 ~>

Điều này không có gì chung với Có thể thay đổi định kỳ PS1 bằng một tập lệnh trong nền không?



Không, không có câu trả lời trong bài đăng đó và tôi hy vọng lời nhắc chỉ thay đổi khi một dấu nhắc mới được hiển thị.
Trêu chọc

Thực sự không có cách nào khả thi để làm những gì bạn yêu cầu, không.
DopeGhoti

1
Điều đó là khả thi nếu giá trị được hiển thị là tĩnh (câu hỏi của OP dường như không cho phép điều đó). Thời gian đã trôi qua có thể được duy trì bằng cách lưu thời gian kỷ nguyên của thời gian trước đó vào một biến vỏ. Thực hiện nó có vẻ rất nhiều công việc mặc dù (một giờ hoặc lâu hơn - có lẽ ai đó sẽ cung cấp một giải pháp đơn giản hơn những gì tôi có trong tâm trí). Câu hỏi này sẽ hữu ích.
Thomas Dickey

Câu trả lời:


10

Một cách để làm điều đó là sử dụng tính năng PROMPT_COMMAND của bash để thực thi mã sửa đổi PS1. Các chức năng dưới đây là một phiên bản cập nhật của đệ trình ban đầu của tôi; cái này sử dụng hai biến môi trường ít hơn và tiền tố chúng với "_PS1_" để cố gắng tránh ghi đè các biến hiện có.

prompt_command() {
  _PS1_now=$(date +%s)
  PS1=$( printf "\[\e[0;32m\]%02d:%02d:%02d \W>\[\e[1;37m\] " \
           $((  ( _PS1_now - _PS1_lastcmd ) / 3600))         \
           $(( (( _PS1_now - _PS1_lastcmd ) % 3600) / 60 )) \
           $((  ( _PS1_now - _PS1_lastcmd ) % 60))           \
       )
  _PS1_lastcmd=$_PS1_now
}
PROMPT_COMMAND='prompt_command'
_PS1_lastcmd=$(date +%s)

Đặt nó vào .bash_profile của bạn để bắt đầu mọi thứ.

Lưu ý rằng bạn phải nhập khá nhanh để có được sleeptham số khớp với tham số nhắc - thời gian thực sự là sự khác biệt giữa các lời nhắc, bao gồm cả thời gian bạn phải nhập lệnh.

00:00:02 ~> sleep 5   ## here I typed really quickly
00:00:05 ~> sleep 3   ## here I took about 2 seconds to enter the command
00:00:10 ~> sleep 30 ## more slow typing
00:01:35 ~>

Bổ sung muộn:

Dựa trên câu trả lời đã bị xóa của @Cyrus, đây là phiên bản không làm lộn xộn môi trường với các biến phụ:

PROMPT_COMMAND='
    _prompt(){
        PROMPT_COMMAND="${PROMPT_COMMAND%-*}-$SECONDS))\""
        printf -v PS1 "\[\e[0;32m\]%02d:%02d:%02d \W>\[\e[1;37m\] " \
                      "$(($1/3600))" "$((($1%3600)/60))" "$(($1%60))"
    }; _prompt "$((SECONDS'"-$SECONDS))\""

Bổ sung muộn:

Bắt đầu từ bash phiên bản 4.2 ( echo $BASH_VERSION), bạn có thể tránh các datecuộc gọi bên ngoài bằng chuỗi định dạng printf mới; thay thế các $(date +%s)mảnh bằng $(printf '%(%s)T' -1). Bắt đầu từ phiên bản 4.3 , bạn có thể bỏ qua -1tham số để dựa vào hành vi "không có đối số nghĩa là ngay bây giờ ".


Đây là thực sự gần gũi. Nó hoạt động khi tôi sao chép / dán từ dấu nhắc bash, nhưng khi tôi cố thêm nó vào .bashrc, nó sẽ in "1451424431: không tìm thấy lệnh"
TeaseDart

có thể một chút quá nhiều có bản sao / dán?
Jeff Schaller

Phiên bản cuối cùng này hoạt động, chính xác những gì tôi muốn! Tôi nghĩ rằng nó có một cái gì đó để làm với cái bẫy của tôi để đặt màu văn bản sau dấu nhắc. Cảm ơn bạn.
Trêu chọc

khi bạn đặt lại, $SECONDSnó sẽ dừng theo dõi thời gian kể từ khi vỏ bắt đầu,
mikeerv

1
@chepner - tốt, chắc chắn, nhưng nó không giữ thời gian của vỏ nữa. đừng hiểu sai ý tôi - tôi đã nêu lên điều này bởi vì đó là một câu trả lời hay - nhưng tôi nghĩ rằng việc xác định lại một vỏ tương tác $SECONDScho mỗi dấu nhắc có khả năng gợi ra những hành vi bất ngờ. bất kỳ hàm shell nào khác có thể sử dụng nó cho bất kỳ lý do nào liên quan đến việc đánh giá thời gian chạy sẽ hoạt động sai.
mikeerv

4
PS1[3]=$SECONDS
PS1='${PS1[!(PS1[1]=!1&(PS1[3]=(PS1[2]=$SECONDS-${PS1[3]})/3600))
   ]#${PS1[3]%%*??}0}$((PS1[3]=(PS1[2]/60%60),  ${PS1[3]})):${PS1[1
   ]#${PS1[3]%%*??}0}$((PS1[3]=(PS1[2]%60),     ${PS1[3]})):${PS1[1
   ]#${PS1[3]%%*??}0}$((PS1[3]=(SECONDS),       ${PS1[3]})):'$PS1

Điều này xử lý định dạng bằng tính toán - vì vậy, trong khi nó mở rộng nhiều lần, nó không thực hiện bất kỳ lớp con hoặc đường ống nào.

Nó chỉ coi $PS1là một mảng và sử dụng các chỉ số cao hơn để lưu trữ / tính toán bất kỳ / tất cả trạng thái cần thiết giữa các lời nhắc. Không có trạng thái vỏ khác bị ảnh hưởng.

00:00:46:[mikeserv@desktop tmp]$
00:00:01:[mikeserv@desktop tmp]$
00:00:00:[mikeserv@desktop tmp]$
00:00:01:[mikeserv@desktop tmp]$
00:00:43:[mikeserv@desktop tmp]$ sleep 10
00:00:33:[mikeserv@desktop tmp]$ sleep 10
00:00:15:[mikeserv@desktop tmp]$
00:00:15:[mikeserv@desktop tmp]$
00:00:02:[mikeserv@desktop tmp]$
00:02:27:[mikeserv@desktop tmp]$

Tôi có thể phá vỡ nó một chút có lẽ ...

Đầu tiên, lưu giá trị hiện tại của $SECONDS:

PS1[3]=$SECONDS

Tiếp theo, xác định $PS1[0]để tự đệ quy theo cách sẽ luôn đặt các giá trị đúng thành $PS1[1-3]đồng thời tự tham chiếu. Để có được phần này, bạn phải xem xét thứ tự các biểu thức shell-math được ước tính. Quan trọng nhất, shell-math luôn là thứ tự kinh doanh cuối cùng cho shell-math. Trước tất cả, shell mở rộng các giá trị. Theo cách này, bạn có thể tham chiếu một giá trị cũ cho biến shell trong biểu thức toán học sau khi gán nó bằng cách sử dụng $.

Đây là một ví dụ đơn giản đầu tiên:

x=10; echo "$(((x+=5)+$x+x))" "$x"

40 15

Shell sẽ đánh giá tuyên bố đó bằng cách thay thế giá trị của $xbất cứ nơi nào $tham chiếu ký hiệu đô la được sử dụng và do đó biểu thức trở thành:

(x+=5)+10+x

... Sau đó, shell thêm 5 vào giá trị của $xvà sau đó mở rộng toàn bộ biểu thức thành x+10+x, trong khi chỉ giữ lại giá trị được gán thực sự trong biến tham chiếu. Và vì vậy, giá trị mở rộng của biểu thức toán học là 40, nhưng giá trị cuối cùng $xlà 15.

Đó phần lớn là cách $PS1phương trình hoạt động tốt, ngoại trừ việc có thêm một mức độ mở rộng / đánh giá toán học được khai thác trong các chỉ số mảng.

PS1='${PS1[!(PS1[1]=!1&(...))]#...}...'

Tôi không thực sự chắc chắn lý do tại sao tôi chọn sử dụng PS1[1]=!1ở đó - tôi đoán có lẽ nó chỉ là thẩm mỹ ngớ ngẩn - nhưng điều này gán 0 cho $PS1[1]trong khi mở rộng nó để thay thế tham số. Giá trị của bitwise AND cho 0 và bất cứ thứ gì khác sẽ luôn là 0, nhưng nó không bị đoản mạch như một boolean &&khi giá trị chính bên trái là 0 và do đó biểu thức chính vẫn được đánh giá mỗi lần. Tất nhiên, đó là điều quan trọng, bởi vì elipsis đầu tiên là nơi đặt các giá trị ban đầu cho $PS1[2,3].

Dù sao, $PS1[1]ở đây được đảm bảo là 0 ngay cả khi nó bị giả mạo w / giữa các lần rút thăm kịp thời. Trong ngoặc đơn có ...

PS1[3]=(PS1[2]=$SECONDS-${PS1[3]})/3600

... $PS1[2]được chỉ định sự khác biệt của $PS1[3]$SECONDS, và $PS1[3]được chỉ định thương số của giá trị đó và 3600. Tất cả các giá trị được khởi tạo ở đây. Và vì thế:

${PS1[1]#${PS1[3]%%*??}0}

... Nếu có ít nhất hai chữ số $PS1[3]thì phần mở rộng bên trong không có giá trị và vì chúng ta biết $PS1[1]là 0 nên nếu $PS1[3]có thể được thay thế thành không có gì, $PS1[1]thì nó cũng được mở rộng thành giá trị của nó. Theo cách này, chỉ các giá trị một chữ số cho mỗi lần lặp của $PS1[3]bài tập sẽ mở rộng một số 0 đứng đầu và $PS1[3]chính nó được mở rộng modulo 60 ngay sau đó trong khi được gán đồng thời giá trị nhỏ hơn tiếp theo cho mỗi giờ, phút, giây.

Rửa sạch và lặp lại, cho đến lần lặp cuối cùng khi $PS1[3]được ghi đè lên w / giá trị hiện tại $SECONDSđể nó có thể được so sánh với $SECONDSmột lần nữa khi lời nhắc được vẽ tiếp theo.


1

Giải pháp tốt nhất tôi tìm thấy cho đến nay là: https://github.com/jichu4n/bash-command-timer

Mà in [ 1s011 | May 25 15:33:44 BST ]hay còn gọi là thời gian đã trôi qua ở phía bên tay phải sau lệnh được thực thi, vì vậy nó không làm lộn xộn PS1 của bạn.

Toàn bộ chuỗi và định dạng thời gian là cấu hình. Ngay cả màu sắc và độ chính xác là cấu hình. Tôi biết nó có thể là một chút nhiều cho một số tối giản ngoài kia, nhưng nó khá tuyệt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.