Chciałbym zaimplementować funkcję w Bash, która zwiększa (i zwraca) liczbę przy każdym wywołaniu. Niestety wydaje się to nietrywialne, ponieważ wywołuję funkcję wewnątrz podpowłoki, w związku z czym nie może ona modyfikować zmiennych powłoki nadrzędnej.
Oto moja próba:
PS_COUNT=0
ps_count_inc() {
let PS_COUNT=PS_COUNT+1
echo $PS_COUNT
}
ps_count_reset() {
let PS_COUNT=0
}
Byłoby to użyte w następujący sposób (a zatem moja potrzeba wywoływania funkcji z podpowłoki):
PS1='$(ps_count_reset)> '
PS2='$(ps_count_inc) '
W ten sposób otrzymałem numerowany monit wieloliniowy:
> echo 'this
1 is
2 a
3 test'
Uroczy. Ale ze względu na wyżej wymienione ograniczenie nie działa.
Niedziałającym rozwiązaniem byłoby zapisanie liczby do pliku zamiast do zmiennej. Spowodowałoby to jednak konflikt między wieloma jednocześnie uruchomionymi sesjami. Oczywiście mogę dołączyć identyfikator procesu powłoki do nazwy pliku. Mam jednak nadzieję, że istnieje lepsze rozwiązanie, które nie zaśmieci mojego systemu dużą ilością plików.
man 1 mktemp
.Odpowiedzi:
Aby uzyskać taki sam wynik, jaki zanotowano w pytaniu, wystarczy:
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.
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:PISMO PISMO:
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:
ROZBIÓR GRAMATYCZNY ZDANIA
$PWD
ALE CO Z WYKORZYSTANIEM?
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 wdash
ish
tak samo dobrze jak wbash
izsh
. 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:Teraz mogę:
DASH DEMO
SH DEMO
To działa tak samo w
bash
lubsh
: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.
źródło
PS2
? To trudna część. Nie sądzę, aby twoje rozwiązanie można było zastosować tutaj. Jeśli uważasz inaczej, pokaż mi, jak to zrobić.PS1
iPS2
są specjalnymi zmiennymi w powłoce, które są drukowane jako wiersz polecenia (wypróbuj to, ustawiającPS1
inną wartość w nowym oknie powłoki), dlatego są one używane zupełnie inaczej niż twój kod. Oto kilka informacji o ich użyciu: linuxconfig.org/bash-prompt-basicsecho 'this
w odpowiedzi na monit, a następnie wyjaśnij, jak zaktualizować wartośćPS2
przed wpisaniem zamykającego pojedynczego cudzysłowu.Dzięki takiemu podejściu (funkcja działająca w podpowłoce) nie będziesz w stanie zaktualizować stanu procesu powłoki głównej bez przechodzenia przez zniekształcenia. Zamiast tego należy ustawić, aby funkcja działała w procesie głównym.
Wartość
PROMPT_COMMAND
zmiennej jest interpretowana jako polecenie, które jest wykonywane przed wydrukowaniemPS1
monitu.Bo
PS2
nie ma nic porównywalnego. Możesz jednak użyć lewy: ponieważ wszystko, co chcesz zrobić, to operacja arytmetyczna, możesz użyć rozszerzenia arytmetycznego, które nie wymaga podpowłoki.Wynik obliczeń arytmetycznych kończy się na pytaniu. Jeśli chcesz go ukryć, możesz przekazać go jako indeks tablicy, który nie istnieje.
źródło
Jest to trochę intensywne we / wy, ale musisz użyć pliku tymczasowego, aby zachować wartość liczby.
Jeśli obawiasz się, że potrzebujesz osobnego pliku na sesję powłoki (co wydaje się drobną obawą; czy naprawdę będziesz wpisywać polecenia wieloliniowe jednocześnie w dwóch różnych powłokach?), Powinieneś użyć,
mktemp
aby utworzyć nowy plik dla każdej posługiwać się.źródło
Nie możesz w ten sposób używać zmiennej powłoki i już rozumiesz dlaczego. Podkładka dziedziczy zmienne dokładnie tak samo, jak proces dziedziczy środowisko: wszelkie wprowadzone zmiany dotyczą tylko niego i jego elementów potomnych, a nie żadnego procesu przodka.
Zgodnie z innymi odpowiedziami najłatwiej jest ukryć te dane w pliku.
Itp.
źródło
mktemp
).PS2
jest rozszerzana przez powłokę. W tej chwili nie masz możliwości zaktualizowania wartości zmiennej w powłoce nadrzędnej.Dla porównania, oto moje rozwiązanie wykorzystujące pliki tymczasowe, które są unikalne dla każdego procesu powłoki i usunięte tak szybko, jak to możliwe (aby uniknąć bałaganu, jak wspomniano w pytaniu):
źródło