Sorunuzda not ettiğiniz aynı çıktıyı elde etmek için gereken tek şey şudur:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Bükülmenize gerek yok. Bu iki satır, POSIX uyumluluğuna yakın herhangi bir şey gibi davranan herhangi bir kabukta bunu yapacak.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Ama bunu sevdim. Ve bunu daha iyi yapan şeyin temellerini göstermek istedim. Bu yüzden biraz düzenledim. /tmp
Şimdilik takıldım ama sanırım kendim için de saklayacağım. Burada:
cat /tmp/prompt
İSTEMİ SENARYO:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Not: son zamanlarda yaş'ı öğrendikten sonra , dün inşa ettim. Herhangi bir nedenle, her argümanın ilk baytını %c
dize ile basmaz - dokümanlar bu format için geniş karakter uzantıları hakkında spesifik olsa da ve belki de ilgili olabilir - ancak%.1s
Her şey bu. Orada iki ana şey var. Ve işte böyle görünüyor:
/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 >
Çözümleme $PWD
Her $PS1
değerlendirildiğinde, isteme $PWD
eklemek için ayrıştırılır ve yazdırılır . Ama tüm $PWD
ekranımı doldurmayı sevmiyorum , bu yüzden tam olarak görmek istediğim geçerli dizine kadar geçerli yoldaki her kırıntısının ilk harfini istiyorum. Bunun gibi:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Burada birkaç adım var:
IFS=/
mevcut $PWD
ve en güvenilir yolu $IFS
bölmek zorundayız /
. Daha sonra onunla uğraşmanıza gerek yok - buradan itibaren tüm bölünmeler, kabuğun bir $@
sonraki komuttaki konumsal parametre dizisi tarafından tanımlanır :
set -- ${PWD%"${last=${PWD##/*/}}"}
Bu biraz zor, ama asıl mesele semboller $PWD
üzerinde bölünüyor olmamız /
. Ayrıca $last
, en sol ve en sağdaki /
eğik çizgi arasında oluşan herhangi bir değerden sonra her şeye atamak için parametre genişletme özelliğini kullanırım . Bu şekilde, eğer sadece bir tanesiysem /
ve sadece bir tanesine /
sahipsem $last
, yine de bütüne eşit $PWD
ve $1
boş kalacağını biliyorum. Bu önemli. Ayrıca atamadan önce $last
kuyruk ucundan $PWD
soyuyorum $@
.
printf "${1+%c/}" "$@"
Yani burada - sürece ${1+is set}
biz printf
ilk %c
her bizim kabuğun argümanlardan haracter - biz sadece mevcut her dizine kurdum $PWD
- daha az üst dizin - on bölünmüş /
. Bu yüzden aslında sadece her dizinin ilk karakterini $PWD
değil, ilk dizini yazdırıyoruz . Ancak $1
bunun, kökte /
veya içinde /
olduğu gibi kaldırılmayacak şekilde ayarlanması durumunda gerçekleştiğini fark etmek önemlidir /etc
.
printf "$last > "
$last
az önce üst dizinimize atadığım değişken. Şimdi bu bizim üst dizinimiz. Son ifadenin yapılıp yapılmadığını yazdırır. >
İyi bir önlem için çok az şey gerekiyor .
ANCAK ENCREMENT HAKKINDA NELER VAR?
Bir de $PS2
şartlılık meselesi var . Daha önce aşağıda bulabileceğiniz bunun nasıl yapılabileceğini daha önce göstermiştim - bu temelde bir kapsam meselesidir. Ancak, bir sürü printf \b
ackpace yapmaya başlamak ve daha sonra karakter sayısını dengelemeye çalışmak istemiyorsanız, biraz daha var ... ugh. Ben de bunu yapıyorum:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Yine ${parameter##expansion}
günü kurtarır. Yine de burada biraz garip - biz kendi değişken şerit aslında değişken ayarlamak. Yeni değerini - orta şerit olarak ayarladık - soyduğumuz küre olarak kullanıyoruz. Anlıyorsun? Biz ##*
herhangi bir şey olabilir son karakteri bizim artım değişkenin kafasından tüm şerit [$((PS2c=0))-9]
. Bu şekilde değerin çıktısını vermememiz garanti edilir, ancak yine de onu atarız. Oldukça havalı - bunu daha önce hiç yapmadım. Ancak POSIX, bunun yapılabilecek en taşınabilir yol olduğunu da bize garanti ediyor.
POSIX tarafından belirlendiğinden ${parameter} $((expansion))
, bu tanımları nerede değerlendirdiğimizden bağımsız olarak ayrı bir alt kabuk içine koymamıza gerek kalmadan mevcut kabukta tutar. O çalışır İşte bu yüzden dash
ve sh
sadece de o olduğu gibi bash
ve zsh
. Kabuk / terminale bağımlı kaçış kullanmıyoruz ve değişkenlerin kendilerini test etmesine izin veriyoruz. Taşınabilir kodu hızlı yapan da budur .
Gerisi oldukça basittir - her seferinde sayacımızı arttırmak $PS2
, bir $PS1
kez daha sıfırlanana kadar değerlendirilir . Bunun gibi:
PS2='$((PS2c=PS2c+1)) > '
Şimdi şunları yapabilirim:
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
Aynı şekilde çalışır bash
veya 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
Yukarıda söylediğim gibi, asıl sorun, hesaplamanızı nerede yaptığınızı düşünmeniz gerektiğidir. Üst kabukta durumu alamazsınız, böylece orada hesaplama yapmazsınız. Durumu alt kabukta alırsınız - işte bu noktada hesaplarsınız. Ancak tanımı üst kabukta yaparsınız.
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
.