พรอมต์ PS1 เพื่อแสดงเวลาที่ผ่านไป


10

ขณะนี้ฉันใช้สิ่งนี้เพื่อแสดงเวลาปัจจุบันใน bash prompt ของฉัน:

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

20:42:23 ~>

เป็นไปได้หรือไม่ที่จะแสดงเวลาที่ผ่านไปตั้งแต่พรอมต์ก่อนหน้า? เช่น:

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

สิ่งนี้ไม่มีอะไรที่เหมือนกันกับมันเป็นไปได้ไหมที่จะเปลี่ยน PS1 เป็นระยะ ๆ โดยสคริปต์ในพื้นหลัง



ไม่ไม่มีคำตอบในโพสต์นั้นและฉันคาดว่าพรอมต์จะเปลี่ยนเฉพาะเมื่อมีข้อความแจ้งใหม่ปรากฏขึ้น
TeasingDart

ไม่มีวิธีที่เป็นไปได้จริง ๆ ในการทำสิ่งที่คุณถามไม่
DopeGhoti

1
เป็นไปได้ถ้าค่าที่แสดงเป็นแบบคงที่ (คำถามของ OP ไม่ปรากฏว่าอนุญาต) เวลาที่ผ่านไปสามารถรักษาได้โดยการบันทึกเวลาของยุคก่อนหน้านี้ในตัวแปรเชลล์ การนำไปใช้ดูเหมือนว่าจะมีงานจำนวนมาก (หนึ่งชั่วโมงหรือมากกว่านั้น - บางทีบางคนอาจจะให้วิธีแก้ปัญหาที่ง่ายกว่าสิ่งที่ฉันมีอยู่ในใจ) คำถามนี้จะเป็นประโยชน์
Thomas Dickey

คำตอบ:


10

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

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)

ใส่สิ่งนั้นลงใน. bash_profile เพื่อเริ่มต้นสิ่งใหม่ ๆ

โปรดทราบว่าคุณต้องพิมพ์อย่างรวดเร็วเพื่อให้sleepพารามิเตอร์จับคู่กับพารามิเตอร์พรอมต์ - เวลาจริง ๆ คือความแตกต่างระหว่างพรอมต์รวมถึงเวลาที่คุณต้องพิมพ์คำสั่ง

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 ~>

นอกจากนี้สาย:

จาก @Cyrus 'คำตอบที่ถูกลบแล้วตอนนี้นี่เป็นรุ่นที่ไม่เกะกะสภาพแวดล้อมด้วยตัวแปรพิเศษ:

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))\""

การเพิ่มสายพิเศษ:

เริ่มต้นใน bash เวอร์ชั่น 4.2 ( echo $BASH_VERSION) คุณสามารถหลีกเลี่ยงการdateโทรภายนอกด้วยสตริงรูปแบบ printf ใหม่ แทนที่$(date +%s)ชิ้น ๆ $(printf '%(%s)T' -1)ด้วย เริ่มต้นในรุ่น 4.3คุณสามารถละเว้น-1พารามิเตอร์พึ่งพา "ไม่มีข้อโต้แย้งหมายถึงตอนนี้พฤติกรรม"


นี่คือใกล้จริง มันทำงานเมื่อฉันคัดลอก / วางจากพรอมต์ bash แต่เมื่อฉันพยายามที่จะเพิ่มลงใน. bashrc ของฉันมันพิมพ์ "1451424431: ไม่พบคำสั่ง"
TeasingDart

อาจจะมีการคัดลอก / วางมากไปหน่อย?
Jeff Schaller

เวอร์ชั่นล่าสุดนี้ทำงานได้ตามที่ฉันต้องการ! ฉันคิดว่ามันมีบางอย่างเกี่ยวข้องกับกับดักของฉันในการตั้งค่าสีข้อความหลังจากพรอมต์ ขอบคุณ.
TeasingDart

เมื่อคุณรีเซ็ต$SECONDSมันจะหยุดการติดตามเวลานับตั้งแต่ที่เชลล์เริ่มทำงาน
mikeserv

1
@chepner - แน่นอน แต่มันไม่ได้ทำให้เวลาของเชลล์กลับมาเหมือนเดิมอีกแล้ว อย่าเข้าใจฉันผิด - ฉันอัปเดตสิ่งนี้เพราะมันเป็นคำตอบที่ดี - แต่ฉันคิดว่าการนิยามเชลล์แบบโต้ตอบใหม่$SECONDSสำหรับทุกการแจ้งเตือนมีแนวโน้มที่จะทำให้เกิดพฤติกรรมที่ไม่คาดคิด ฟังก์ชั่นเชลล์อื่น ๆ ที่อาจใช้งานไม่ว่าด้วยเหตุผลใดก็ตามที่เกี่ยวข้องกับการประเมินเวลาทำงานจะทำงานผิดปกติ
mikeserv

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

สิ่งนี้จัดการการจัดรูปแบบโดยการคำนวณ - ดังนั้นในขณะที่มันขยายหลาย ๆ ครั้งมันไม่ทำ subshells หรือไปป์ใด ๆ

มันเพียงแค่ถือว่า$PS1เป็นอาร์เรย์และใช้ดัชนีที่สูงขึ้นในการจัดเก็บ / คำนวณใด ๆ / ทุกสถานะที่จำเป็นระหว่างการแจ้งให้ ไม่มีสถานะเชลล์อื่นใดที่ได้รับผลกระทบ

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

ฉันสามารถทำลายมันลงได้เล็กน้อย ...

ก่อนอื่นให้บันทึกค่าปัจจุบันของ$SECONDS:

PS1[3]=$SECONDS

ถัดไปให้กำหนด$PS1[0]ตนเองแบบเรียกซ้ำในลักษณะที่จะตั้งค่าที่ถูกต้องเสมอ$PS1[1-3]ในขณะที่การอ้างอิงตนเองพร้อมกัน ในการรับส่วนนี้คุณจะต้องพิจารณาลำดับที่นิพจน์เชลล์ - คณิตศาสตร์ได้รับการประเมิน สิ่งที่สำคัญที่สุดเชลล์เชลล์คือคำสั่งสุดท้ายของธุรกิจเชลล์เชลล์ ก่อนอื่นเชลล์จะขยายค่า $ด้วยวิธีนี้คุณสามารถอ้างอิงเก่าค่าสำหรับเปลือกตัวแปรในนิพจน์คณิตศาสตร์หลังจากที่กำหนดโดยใช้

นี่คือตัวอย่างง่ายๆก่อน:

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

40 15

เชลล์จะประเมินข้อความนั้นโดยการแทนที่ค่าแรกของ$xทุก ๆ ที่ที่$ใช้การอ้างอิงเครื่องหมายดอลลาร์และดังนั้นการแสดงออกจึงกลายเป็น:

(x+=5)+10+x

... จากนั้นเชลล์จะเพิ่ม 5 ให้กับมูลค่า$xและหลังจากนั้นจะขยายนิพจน์ทั้งหมดไปx+10+xในขณะที่ยังคงรักษาเฉพาะค่าที่กำหนดจริงในตัวแปรอ้างอิงเท่านั้น ค่าที่ขยายได้ของนิพจน์ทางคณิตศาสตร์คือ 40 แต่ค่าสูงสุด$xคือ 15

นั่นคือวิธีการที่$PS1สมการส่วนใหญ่ทำงานได้ดียกเว้นว่าจะมีการขยาย / ประเมินผลทางคณิตศาสตร์ในระดับอาเรย์เพิ่มเติม

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

ฉันไม่แน่ใจจริงๆว่าทำไมฉันถึงเลือกที่จะใช้ที่PS1[1]=!1นั่น - ฉันคิดว่ามันอาจจะเป็นแค่ความสวยงามที่โง่เง่า - แต่สิ่งนี้กำหนดให้ 0 $PS1[1]ในขณะที่ขยายเพื่อทดแทนพารามิเตอร์ ค่าของ bitwise AND สำหรับ 0 และสิ่งอื่น ๆ จะเป็น 0 เสมอ แต่มันจะไม่ลัดวงจรเหมือนบูลีน&&ทำเมื่อค่าหลักซ้ายสุดคือ 0 ดังนั้นนิพจน์เชิงซ้อนจะได้รับการประเมินทุกครั้ง นั่นเป็นสิ่งสำคัญแน่นอนเพราะอีลิสซิแรกนั้นเป็นที่ที่ค่าเริ่มต้น$PS1[2,3]ถูกตั้งค่า

อย่างไรก็ตาม$PS1[1]มั่นใจได้ว่าที่นี่จะเป็น 0 แม้ว่าจะมีการเปลี่ยนแปลงโดยไม่แจ้งให้ทราบ ภายในวงเล็บมี ...

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

... $PS1[2]ได้รับการกำหนดความแตกต่างของ$PS1[3]และ$SECONDSและ$PS1[3]ได้รับการหารความฉลาดของค่านั้นและ 3600 ค่าทั้งหมดจะเริ่มต้นได้ที่นี่ และอื่น ๆ :

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

... ถ้ามีอย่างน้อยสองหลักใน$PS1[3]นั้นการขยายตัวภายในจะเป็นโมฆะและเพราะเรารู้ว่า$PS1[1]เป็น 0 ดังนั้นถ้า$PS1[3]สามารถถูกแทนที่ด้วยอะไรก็ได้ดังนั้นก็เป็น$PS1[1]อย่างอื่นมันก็จะขยายไปตามมูลค่าของมัน ด้วยวิธีนี้เฉพาะค่าตัวเลขหลักเดียวสำหรับการ$PS1[3]กำหนดซ้ำแต่ละครั้งจะขยายศูนย์นำหน้าและ$PS1[3]ขยายตัวเองแบบโมดูโล 60 ทันทีหลังจากนั้นในขณะที่ได้รับมอบหมายพร้อมกันค่าที่น้อยกว่าต่อไปสำหรับแต่ละชั่วโมงนาทีวินาที

ล้างและทำซ้ำจนกว่าจะมีการทำซ้ำครั้งล่าสุดเมื่อ$PS1[3]ถูกเขียนทับด้วยค่าปัจจุบัน$SECONDSเพื่อที่จะสามารถเปรียบเทียบได้$SECONDSอีกครั้งเมื่อมีการแจ้งให้วาดถัดไป


1

ทางออกที่ดีที่สุดที่ฉันพบคือ: https://github.com/jichu4n/bash-command-timer

ซึ่งพิมพ์[ 1s011 | May 25 15:33:44 BST ]เวลา aka ผ่านทางด้านขวามือหลังจากคำสั่งดำเนินการจึงไม่ถ่วงคุณ PS1

รูปแบบสตริงและเวลาทั้งหมดสามารถกำหนดค่าได้ แม้แต่สีและความแม่นยำก็สามารถกำหนดค่าได้ ฉันรู้ว่ามันอาจจะเล็กน้อยสำหรับการตกแต่งมินิมัลลิสต์ แต่มันเจ๋งมาก

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