Geçen süreyi göstermek için PS1 istemi


10

Şu anda bash istemimde geçerli saati görüntülemek için bunu kullanıyorum:

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

20:42:23 ~>

Önceki istemden bu yana geçen süreyi görüntülemek mümkün müdür? Gibi:

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

Bunun ortak bir yanı yok Arka planda bir betik ile PS1'i periyodik olarak değiştirmek mümkün mü?



Hayır, bu gönderide cevap yok ve istemin yalnızca yeni bir istem görüntülendiğinde değişmesini bekliyorum.
TeasingDart

Sorduğunuz şeyi yapmanın gerçekten mümkün bir yolu yok, hayır.
DopeGhoti

1
Görüntülenen değerin statik olması mümkündür (OP'nin sorusu buna izin vermedi). Geçen süre, önceki zamanın dönem zamanını bir kabuk değişkenine kaydederek korunabilir. Gerçi uygulamak çok iş gibi görünüyor (bir saat kadar - belki biri aklımdakilerden daha basit bir çözüm sağlayacaktır). Bu soru yardımcı olacaktır.
Thomas Dickey

Yanıtlar:


10

Bunu yapmanın bir yolu, PS1'i değiştiren kodu çalıştırmak için bash'ın PROMPT_COMMAND özelliğini kullanmak olacaktır. Aşağıdaki işlev, orijinal gönderimin güncellenmiş bir sürümüdür; bu, daha az iki ortam değişkeni kullanır ve mevcut değişkenlerin zorlanmasını önlemek için bu değişkenlerin önüne "_PS1_" ekler.

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)

İşleri başlatmak için bunu .bash_profile dosyanıza koyun.

sleepParametrenin, bilgi istemi parametresiyle eşleşmesi için oldukça hızlı bir şekilde yazmanız gerektiğini unutmayın - zaman, komut istemi için geçen süre de dahil olmak üzere bilgi istemleri arasındaki farktır.

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

Geç ekleme:

@Cyrus'un şimdi silinmiş cevabına dayanarak, çevreyi fazladan değişkenlerle karıştırmayan bir sürüm:

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

Ekstra geç ekleme:

Bash sürüm 4.2 ( echo $BASH_VERSION) 'den başlayarak,date yeni bir printf format dizesiyle harici çağrılardan kaçınabilirsiniz ; $(date +%s)parçaları ile değiştirin $(printf '%(%s)T' -1). Sürüm 4.3'ten başlayarak , -1parametrenin " şimdi hiçbir argüman anlamına gelmez " davranışına güvenmesini engelleyebilirsiniz .


Bu çok yakın. Bir bash isteminden kopyaladığımda / yapıştırdığımda çalışır, ancak .bashrc'ye eklemeye çalıştığımda "1451424431: komut bulunamadı" yazdırılıyor
TeasingDart

belki biraz fazla kopya / yapıştırılmış var?
Jeff Schaller

Bu son sürüm tam olarak istediğim gibi çalıştı! İstendiğinde metin rengini ayarlamak için tuzağımla ilgili bir şey olduğunu düşünüyorum. Teşekkür ederim.
TeasingDart

sıfırladığınızda $SECONDS, kabuk başladığından bu yana geçen süreyi izlemek için durur
mikeserv

1
@ chepner - elbette, ama kabuğun zamanını bir daha asla tutmuyor. beni yanlış anlamayın - bunu iptal ettim, çünkü bu iyi bir cevap - ama $SECONDSher istem için etkileşimli bir kabuğun yeniden tanımlanmasının beklenmedik davranışlar ortaya çıkmasının muhtemel olduğunu düşünüyorum . çalışma zamanının değerlendirilmesi ile ilişkili herhangi bir nedenle onu kullanabilecek herhangi bir kabuk işlevi hatalı davranacaktır.
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

Bu, biçimlendirmeyi hesaplamaya göre yapar - bu nedenle, birkaç kez genişlerken, alt kabuklar veya borular yapmaz.

Sadece $PS1bir dizi gibi davranır ve bilgi istemleri arasında gerekli tüm durumları saklamak / hesaplamak için daha yüksek endeksleri kullanır. Başka hiçbir kabuk durumu etkilenmez.

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

Belki biraz parçalayabilirim ...

İlk olarak, şu anki değerini kaydedin $SECONDS:

PS1[3]=$SECONDS

Ardından, eşzamanlı olarak kendini referans alırken $PS1[0]her zaman doğru değerleri ayarlayacak şekilde özyinelemeli olarak tanımlayın $PS1[1-3]. Bu bölümü elde etmek için kabuk-matematik ifadelerinin değerlendirilme sırasını dikkate almanız gerekir. En önemlisi, kabuk-matematik her zaman kabuk-matematik için işin son sırasıdır. Her şeyden önce, kabuk değerleri genişletir. Bu yolla, kullanarak matematik ifadesinde bir kabuk değişkeni için eski bir değere başvurabilirsiniz $.

İlk önce basit bir örnek:

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

40 15

Kabuk önce değerinin değiştirilmesi ile bu açıklama değerlendirecektir $xyerde $ifade olur böylece dolar işareti referans kullanılır ve:

(x+=5)+10+x

... sonra kabuk değerine 5 ekler $xve daha sonra tüm ifadeyi genişletir x+10+x, ancak yalnızca referans değişkeninde atanmış değeri korur. Ve böylece matematik ifadesinin genişletilmiş değeri 40, ancak nihai değeri $x15'tir.

Yani ne kadar büyük ölçüde $PS1denklemi matematik genişleme / dizi indekslerinde sömürülen değerlendirmenin bir başka düzeyde olduğunu haricinde, hem de çalışıyor.

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

Neden orada kullanmayı seçtiğimden gerçekten emin değilim PS1[1]=!1- sanırım muhtemelen aptalca bir estetikti - ama bu $PS1[1]parametre yerine koyma için genişletirken 0'ı atar . Bit için AND değeri 0 ve başka bir şey her zaman 0 olacaktır, ancak &&en soldaki birincil 0 olduğunda boole yaptığı gibi kısa devre yapmaz ve bu nedenle parantez ifadesi her seferinde değerlendirilir. Bu elbette önemlidir, çünkü ilk elipsis başlangıç ​​değerlerinin $PS1[2,3]ayarlandığı yerdir .

Her neyse, $PS1[1]burada hızlı çekilişler arasında kurcalanmış olsa bile 0 olduğundan emin olabilirsiniz. Parantez içinde ...

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

... $PS1[2]farkını atanır $PS1[3]ve $SECONDSve $PS1[3]bu değeri ve 3600 Tüm değerler burada başlatılır ait katsayısı atanır. Ve bu yüzden:

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

... eğer $PS1[3]iç genişleme en az iki hane varsa, boştur ve $PS1[1]0 olduğunu bildiğimizden , $PS1[3]hiçbir şeye ikame edilemezse, $PS1[1]başka bir değere de genişletilir. Bu şekilde, $PS1[3]atamaların her bir tekrarı için sadece tek haneli değerler önde gelen sıfırı genişletir ve $PS1[3]kendiliğinden hemen sonra modü 60'a genişletilir, aynı zamanda her saat, dakika, saniye için bir sonraki art arda daha küçük değer atanır.

Durulayın ve $PS1[3]geçerli değerle üzerine yazılan son yinelemeye kadar , istemin bir sonraki çizildiğinde bir kez daha $SECONDSkarşılaştırılabilmesi için tekrarlayın $SECONDS.


1

Şimdiye kadar bulduğum en iyi çözüm şudur: https://github.com/jichu4n/bash-command-timer

[ 1s011 | May 25 15:33:44 BST ]Yürütülen komuttan sonra sağ taraftaki geçen süreyi aka yazdırır , böylece PS1'i karıştırmaz.

Tüm dize ve saat biçimi yapılandırılabilir. Renk ve hassasiyet bile yapılandırılabilir. Biraz minimalist için biraz fazla olabileceğini biliyorum, ama oldukça havalı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.