Untuk mendapatkan hasil yang sama seperti yang Anda catat dalam pertanyaan Anda, yang diperlukan hanyalah ini:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Anda tidak perlu memutarbalikkan. Kedua baris tersebut akan melakukan semuanya dalam shell yang berpura-pura mendekati kompatibilitas POSIX.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Tapi saya suka ini. Dan saya ingin menunjukkan dasar-dasar apa yang membuat pekerjaan ini sedikit lebih baik. Jadi saya sedikit mengedit ini. Saya memasukkannya /tmp
untuk saat ini tetapi saya pikir saya akan menyimpannya sendiri juga. Itu disini:
cat /tmp/prompt
PROMPT SCRIPT:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Catatan: setelah baru-baru ini belajar tentang yash , saya membangunnya kemarin. Untuk alasan apa pun itu tidak mencetak byte pertama dari setiap argumen dengan %c
string - meskipun dokumen khusus tentang ekstensi wide-char untuk format itu dan jadi itu mungkin terkait - tetapi tidak apa-apa dengan%.1s
Itu semuanya. Ada dua hal utama yang terjadi di sana. Dan seperti inilah tampilannya:
/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 >
PARSING $PWD
Setiap kali $PS1
dievaluasi itu diurai dan dicetak $PWD
untuk menambah prompt. Tetapi saya tidak suka seluruh $PWD
kerumunan layar saya, jadi saya ingin hanya huruf pertama dari setiap remah roti di jalur saat ini ke direktori saat ini, yang ingin saya lihat secara penuh. Seperti ini:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Ada beberapa langkah di sini:
IFS=/
kita harus membagi arus $PWD
dan cara yang paling dapat diandalkan untuk melakukannya adalah dengan $IFS
membagi /
. Tidak perlu repot dengan itu sama sekali sesudahnya - semua pemisahan dari sini keluar akan ditentukan oleh $@
array parameter posisi shell di perintah berikutnya seperti:
set -- ${PWD%"${last=${PWD##/*/}}"}
Jadi yang satu ini sedikit rumit, tetapi hal utama adalah bahwa kita membelah $PWD
pada /
simbol. Saya juga menggunakan ekspansi parameter untuk menetapkan $last
segalanya setelah nilai apa pun yang terjadi antara /
slash paling kiri dan paling kanan . Dengan cara ini saya tahu bahwa jika saya hanya /
punya dan hanya punya satu /
maka $last
akan tetap sama dengan keseluruhan $PWD
dan $1
akan kosong. Ini penting. Saya juga melepas $last
dari ujung ekor $PWD
sebelum menugaskan $@
.
printf "${1+%c/}" "$@"
Jadi di sini - selama ${1+is set}
kita printf
adalah karakter pertama %c
dari setiap argumen shell kita - yang baru saja kita atur untuk setiap direktori saat ini $PWD
- dikurangi direktori teratas - terpecah /
. Jadi pada dasarnya kita hanya mencetak karakter pertama dari setiap direktori $PWD
tetapi yang paling atas. Penting untuk menyadari bahwa ini hanya terjadi jika $1
disetel sama sekali, yang tidak akan terjadi pada saat root /
atau dihilangkan dari /
seperti pada /etc
.
printf "$last > "
$last
adalah variabel yang baru saja saya ditugaskan ke direktori teratas kami. Jadi sekarang ini adalah direktori teratas kami. Ini mencetak apakah pernyataan terakhir lakukan atau tidak. Dan butuh sedikit yang rapi >
untuk mengukur baik.
TAPI APA TENTANG PENINGKATAN?
Dan kemudian ada masalah $PS2
kondisional. Saya telah menunjukkan sebelumnya bagaimana hal ini dapat dilakukan yang masih dapat Anda temukan di bawah - ini pada dasarnya masalah ruang lingkup. Tapi ada sedikit lebih dari itu kecuali jika Anda ingin mulai melakukan banyak printf \b
ruang dan kemudian mencoba untuk menyeimbangkan jumlah karakter mereka ... ugh. Jadi saya melakukan ini:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Sekali lagi, ${parameter##expansion}
hematlah hari itu. Agak aneh di sini - kita sebenarnya mengatur variabel sementara kita menghapusnya sendiri. Kami menggunakan nilai barunya - setel strip tengah - sebagai gumpalan yang darinya kami strip. Kamu melihat? Kami ##*
menghapus semua dari kepala variabel kenaikan kami ke karakter terakhir yang dapat berupa apa saja [$((PS2c=0))-9]
. Kami dijamin dengan cara ini untuk tidak menampilkan nilai, namun kami masih menetapkannya. Ini keren - saya belum pernah melakukannya sebelumnya. Tetapi POSIX juga menjamin kita bahwa ini adalah cara paling portabel yang bisa dilakukan.
Dan terima kasih kepada POSIX yang ditentukan ${parameter} $((expansion))
yang membuat definisi ini di shell saat ini tanpa mengharuskan kita mengaturnya dalam subkulit yang terpisah, terlepas dari di mana kita mengevaluasinya. Dan inilah mengapa ini bekerja dash
dan sh
sama baiknya dengan di bash
dan zsh
. Kami tidak menggunakan shell / terminal dependent escapes dan kami membiarkan variabel menguji sendiri. Itulah yang membuat kode portabel cepat.
Sisanya cukup sederhana - cukup tambahkan penghitung kami untuk setiap kali $PS2
dievaluasi sampai $PS1
sekali lagi atur ulang. Seperti ini:
PS2='$((PS2c=PS2c+1)) > '
Jadi sekarang saya bisa:
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
Ia bekerja sama di bash
atau 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
Seperti yang saya katakan di atas, masalah utama adalah Anda harus mempertimbangkan di mana Anda melakukan perhitungan. Anda tidak mendapatkan status di shell induk - jadi Anda tidak menghitung di sana. Anda mendapatkan status dalam subkulit - jadi di situlah Anda menghitung. Tapi Anda melakukan definisi di shell induk.
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
.