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 $PS1
bir 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 $x
yerde $
ifade olur böylece dolar işareti referans kullanılır ve:
(x+=5)+10+x
... sonra kabuk değerine 5 ekler $x
ve 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 $x
15'tir.
Yani ne kadar büyük ölçüde $PS1
denklemi 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 $SECONDS
ve $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 $SECONDS
karşılaştırılabilmesi için tekrarlayın $SECONDS
.