
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 /tmpna 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 %ccią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 $PS1jest oceniany, analizuje i drukuje, $PWDaby dodać do monitu. Ale nie podoba mi się to, że cały $PWDekran 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 $PWDi najbardziej niezawodny sposób, aby to zrobić, używając $IFSpodział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ę $PWDna /symbole. Korzystam również z rozszerzania parametrów, aby przypisywać $lastwszystko 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 $lastnadal będzie równa całości $PWDi $1będzie pusta. To ma znaczenie Usuwam również $lastz końca ogona $PWDprzed przypisaniem go do $@.
printf "${1+%c/}" "$@"
Więc tutaj - o ile ${1+is set}jesteśmy printfpierwszymi %ccechami argumentów każdej powłoki - które właśnie ustawiliśmy dla każdego katalogu w naszym bieżącym $PWDkatalogu - bez katalogu głównego - podzieliliśmy się /. Tak więc zasadniczo drukujemy tylko pierwszy znak każdego katalogu w, $PWDoprócz pierwszego. Ważne jest jednak, aby zdawać sobie sprawę, że dzieje się tak tylko wtedy, gdy $1zostanie w ogóle ustawiony, co nie nastąpi w katalogu głównym /lub w jednym usuniętym z /takiego jak /etc.
printf "$last > "
$lastto 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 $PS2warunkowa. 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 \bpotwierdzają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 dashi shtak samo dobrze jak w bashi 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 $PS2jest oceniany, aż $PS1ponownie 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 bashlub 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.