Jak całkowicie zrestartować skrypt z poziomu samego skryptu

22

Konfiguruję skrypt powłoki z menu i podmenu, opcji itp. Ale w każdym menu / podmenu / etc potrzebuję opcji „Wróć do menu głównego”.

Mam już skonfigurowane menu i działa dobrze, ale potrzebuję sposobu, aby po prostu ponownie uruchomić skrypt od zera, zresetować wszystkie zmienne itp.

Lub sposób na wyjście z bieżącego skryptu i ponowne uruchomienie go.

Próbowałem to zrobić:

ScriptLoc=$(readlink -f "$0")
./ScriptLoc

Ale to zaczyna „nowy” skrypt w „starym” skrypcie, więc kiedy wychodzę z „nowego” skryptu, wraca do „starego” skryptu (jeśli to ma sens). To jest skrypt wewnątrz czegoś w rodzaju skryptu.

Czy ktoś ma pomysł, jak całkowicie go zrestartować?

Moonbloom
źródło
Tak powinno być $ScriptLoc: ./ScriptLocszuka skryptu o tej nazwie w bieżącym katalogu.
poolie

Odpowiedzi:

10

Możesz użyć czegoś takiego:

$(basename $0) && exit

$(basename $0)utworzy nową instancję bieżącego skryptu i exitwyjdzie z bieżącej instancji skryptu.

Oto skrypt testowy, który podkreśla powyższą metodę:

#!/bin/bash

if ! [[ $count =~ ^[0-9]+$ ]] ; then
    export count=0
fi

echo $count

if [ $count -le 10 ]; then
    count=$(echo "$count+1" | bc)   
    ./$(basename $0) && exit #this will run if started from the same folder
fi

echo "This will be printed only when the tenth instance of script is reached"

Jeśli nie użyjesz export count=0(która countzmienia się w zmienną środowiskową) i użyjesz tylko count=0(która tworzy contzmienną skryptu lokalnego), skrypt nigdy się nie zatrzyma.

Radu Rădeanu
źródło
&& exitzakończy działanie tylko wtedy, gdy skrypt się powiedzie. Jeśli na przykład skrypt nie jest wykonywalny lub występuje błąd składniowy, prawdopodobnie się po prostu zakręci.
poolie
Dodano ./ do basenuame - w przeciwnym razie piękne rozwiązanie - naprawdę fajnie, zdefiniuj +1.
Lefty G Balogh
4

Wiarygodne uzyskanie aktualnie wykonywanego skryptu jest trudniejsze niż mogłoby się wydawać. Zobacz http://mywiki.wooledge.org/BashFAQ/028 .

Zamiast tego możesz zrobić coś takiego:

main_menu() { 
    printf '1. Do something cool\n'
    printf '2. Do something awesome\n'
    : ... etc
}

some_sub_sub_menu() {
    ...
    printf 'X. Return to main menu\n'
    ...
    if [[ $choice = [Xx] ]]; then
        exit 255
    fi
}

while true; do
    (main_menu)
    res=$?
    if (( res != 255 )); then
        break
    fi
done

Zasadniczo uruchamiasz funkcję main_menu w podpowłoce, więc jeśli wyjdziesz z main_menu lub dowolnego z podmenu, opuścisz podpowłokę, a nie główną powłokę. status wyjścia 255 jest tutaj wybrany, aby oznaczać „idź ponownie”. Każdy inny status wyjścia wyłamie się z nieskończonej pętli.

geirha
źródło