Aby uzyskać taki sam wynik, jaki zanotowano w pytaniu, wystarczy:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
Nie musisz się wykręcać. Te dwie linie zrobią to wszystko w dowolnej powłoce, która udaje, że jest bliska kompatybilności z POSIX.
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
Ale mi się podobało. Chciałem też zademonstrować podstawy tego, co czyni tę pracę nieco lepszą. Więc trochę to zredagowałem. Wcisnąłem to /tmp
na razie, ale myślę, że też zatrzymam to dla siebie. To tu:
cat /tmp/prompt
PISMO PISMO:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
Uwaga: niedawno dowiedziałem się o yash , zbudowałem go wczoraj. Z jakiegokolwiek powodu nie wypisuje pierwszego bajtu każdego argumentu z %c
ciągiem znaków - chociaż dokumentacja była specyficzna dla rozszerzeń szerokich znaków dla tego formatu i dlatego może być spokrewniona - ale działa dobrze z%.1s
To wszystko. Działają tam dwie główne rzeczy. I tak to wygląda:
/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 >
ROZBIÓR GRAMATYCZNY ZDANIA $PWD
Za każdym razem, gdy $PS1
jest oceniany, analizuje i drukuje, $PWD
aby dodać do monitu. Ale nie podoba mi się to, że cały $PWD
ekran jest zatłoczony, więc chcę tylko pierwszą literę każdej bułki tartej w bieżącej ścieżce do bieżącego katalogu, który chciałbym zobaczyć w całości. Lubię to:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
Tutaj jest kilka kroków:
IFS=/
będziemy musieli podzielić obecny $PWD
i najbardziej niezawodny sposób, aby to zrobić, używając $IFS
podziału /
. Po tym nie musisz się już tym przejmować - całe dzielenie od teraz będzie definiowane przez $@
tablicę parametrów pozycyjnych powłoki w następnej komendzie, np .:
set -- ${PWD%"${last=${PWD##/*/}}"}
To jest trochę trudne, ale najważniejsze jest to, że dzielimy się $PWD
na /
symbole. Korzystam również z rozszerzania parametrów, aby przypisywać $last
wszystko po dowolnej wartości występującej między /
ukośnikiem od lewej i prawej . W ten sposób wiem, że jeśli jestem tylko /
i mam tylko jedną, /
to $last
nadal będzie równa całości $PWD
i $1
będzie pusta. To ma znaczenie Usuwam również $last
z końca ogona $PWD
przed przypisaniem go do $@
.
printf "${1+%c/}" "$@"
Więc tutaj - o ile ${1+is set}
jesteśmy printf
pierwszymi %c
cechami argumentów każdej powłoki - które właśnie ustawiliśmy dla każdego katalogu w naszym bieżącym $PWD
katalogu - bez katalogu głównego - podzieliliśmy się /
. Tak więc zasadniczo drukujemy tylko pierwszy znak każdego katalogu w, $PWD
oprócz pierwszego. Ważne jest jednak, aby zdawać sobie sprawę, że dzieje się tak tylko wtedy, gdy $1
zostanie w ogóle ustawiony, co nie nastąpi w katalogu głównym /
lub w jednym usuniętym z /
takiego jak /etc
.
printf "$last > "
$last
to zmienna, którą właśnie przypisałem do naszego głównego katalogu. Więc teraz jest to nasz główny katalog. Drukuje, czy zrobiła to ostatnia instrukcja. I >
na dobrą sprawę trzeba trochę schludnie .
ALE CO Z WYKORZYSTANIEM?
A potem jest kwestia $PS2
warunkowa. Wcześniej pokazałem, jak można to zrobić, co wciąż można znaleźć poniżej - jest to zasadniczo kwestia zakresu. Ale jest jeszcze coś więcej, chyba że chcesz zacząć robić kilka miejsc printf \b
potwierdzających, a następnie próbować zrównoważyć liczbę ich postaci ... eee. Więc robię to:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
Znowu ${parameter##expansion}
ratuje dzień. Jest to jednak trochę dziwne - ustawiamy zmienną, podczas gdy usuwamy ją z siebie. Używamy jej nowej wartości - zestawu środkowego paska - jako globu, z którego usuwamy. Zobaczysz? Mamy ##*
rozebrać wszystko z głowy naszej zmiennej przyrostu do ostatniego znaku, który może być coś z [$((PS2c=0))-9]
. W ten sposób gwarantujemy, że nie wyprowadzimy wartości, a jednak nadal ją przypisujemy. To całkiem fajne - nigdy wcześniej tego nie robiłem. Ale POSIX gwarantuje nam również, że jest to najbardziej przenośny sposób, w jaki można to zrobić.
I to dzięki specyfikacji POSIX, ${parameter} $((expansion))
która przechowuje te definicje w bieżącej powłoce bez konieczności umieszczania ich w osobnej podpowłoce, niezależnie od tego, gdzie je oceniamy. I dlatego działa w dash
i sh
tak samo dobrze jak w bash
i zsh
. Nie używamy żadnych ucieczek zależnych od powłoki / terminala i pozwalamy, aby zmienne same się testowały. To sprawia, że przenośny kod jest szybki.
Reszta jest dość prosta - wystarczy zwiększyć nasz licznik za każdym razem, gdy $PS2
jest oceniany, aż $PS1
ponownie go zresetuje. Lubię to:
PS2='$((PS2c=PS2c+1)) > '
Teraz mogę:
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
To działa tak samo w bash
lub 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
Jak powiedziałem powyżej, głównym problemem jest to, że musisz rozważyć miejsce wykonywania obliczeń. Nie otrzymujesz stanu w powłoce nadrzędnej - więc tam nie obliczasz. Otrzymujesz stan w podpowłoce - więc tam obliczasz. Ale robisz definicję w powłoce nadrzędnej.
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
.