Próbuję napisać funkcję, która zastąpi funkcjonalność exit
wbudowanego systemu, aby uniemożliwić mi wyjście z terminala.
Próbowałem użyć SHLVL
zmiennej środowiskowej, ale wydaje się, że nie zmienia się w podpowłokach:
$ echo $SHLVL
1
$ ( echo $SHLVL )
1
$ bash -c 'echo $SHLVL'
2
Moja funkcja jest następująca:
exit () {
if [[ $SHLVL -eq 1 ]]; then
printf '%s\n' "Nice try!" >&2
else
command exit
fi
}
Nie pozwoli mi to jednak korzystać z exit
podpowłok:
$ exit
Nice try!
$ (exit)
Nice try!
Jaka jest dobra metoda wykrywania, czy jestem w podpowłoce?
(...)
dziedziczą wszystkie właściwości procesu nadrzędnego. Podane odpowiedzi są bardziej niezawodnymi rozwiązaniami do określania poziomu powłoki.BASH_SUBSHELL
odpowiedź (nawet jeśli jest kontrowersyjna) nie dotyczyłaby tego pytania.Odpowiedzi:
W bash możesz porównać
$BASHPID
do$$
Jeśli nie jesteś bash,
$$
powinieneś pozostać taki sam w podpowłoce, więc potrzebujesz innego sposobu uzyskania faktycznego identyfikatora procesu.Jednym ze sposobów na uzyskanie faktycznego pid jest
sh -c 'echo $PPID'
. Jeśli po prostu umieścisz to na prostym( … )
ekranie, może się wydawać, że nie działa, ponieważ twoja powłoka zoptymalizowała rozwidlenie. Wypróbuj dodatkowe polecenia no-op,( : ; sh -c 'echo $PPID'; : )
aby przekonać się, że podpowłoka jest zbyt skomplikowana, aby ją zoptymalizować. Podziękowania dla John1024 za przepełnienie stosu za to podejście.źródło
(sh -c 'echo $PPID'; : )
- patrz mój komentarz na odpowiedź John1024 użytkownika .Jak o
BASH_SUBSHELL
?źródło
[powinien to być komentarz, ale moje komentarze są zwykle usuwane przez moderatorów, więc pozostanie to odpowiedzią, że mógłbym użyć go jako odniesienia, nawet jeśli zostanie usunięty]
Używanie
BASH_SUBSHELL
jest całkowicie zawodne, ponieważ może być ustawione tylko na 1 w niektórych podpowłokach, a nie we wszystkich podpowłokach.Przed twierdzeniem, że podproces, w którym uruchamiane jest polecenie potoku, nie jest naprawdę prawdziwą podpowłoką, rozważ ten
man bash
fragment:i praktyczne implikacje - to, czy fragment skryptu jest uruchamiany podproces, czy nie, co jest niezbędne, a nie jakaś sprzeczność terminologiczna.
Jedynym rozwiązaniem, jak już wyjaśniono w odpowiedziach na to pytanie, jest sprawdzenie, czy
$BASHPID
jest równe,$$
czy przenośne, ale znacznie mniej wydajne:źródło
BASH_SUBSHELL
jest ustawiony dość niezawodnie, ale prawidłowe uzyskanie jego wartości jest niepewne. Zwróć uwagę na to, co mówią dokumenty : „Zwiększone o jeden w obrębie każdej podpowłoki lub środowiska podpowłoki, gdy powłoka zaczyna wykonywać się w tym środowisku. ” Myślę, że w przykładzie potoku bash nie zaczął jeszcze działać w tej podpowłoce, gdy zmienna jest rozwijana. Możesz porównaćecho $BASH_VERSION
zdeclare -p BASH_VERSION
- ten ostatni powinien niezawodnie wyprowadzać 1 zeval 'echo $BASH_SUBSHELL $BASHPID' | cat
że wypisze 1 dlaBASH_SUBSHELL
, ponieważ zmienna jest rozwijana po rozpoczęciu wykonywania.subshell_level
naprawdę jest odroczona w przypadku rurociągów pierwszego planu , co prawdopodobnie ma jakiś powód, ale którego nie jestem w stanie zrozumieć ;-)echo $$ $BASHPID $BASH_SUBSHELL | cat
.