Jak zapętlić instrukcję if w bash?

Chcę, aby użytkownik został poproszony o pytanie, a następnie udzielił odpowiedzi, która zostanie zapisana pod zmienną o nazwie i, a jeśli odpowiedź (która jest plikiem) istnieje i jest zapisywalny, czyta go i grepsuje elementy w pliku i zapisuje je w nowym. Jeśli plik nie istnieje lub użytkownik nie ma wystarczających uprawnień do tego pliku, pojawi się ostrzeżenie, program uśpi się na 3 sekundy i pętle zostaną ponownie uruchomione. Dlaczego to nie działa? Ostrzeżenie po prostu nie zniknie, podobnie jak pętla.

echo "$(tput setaf 4) Tell me where the file is:" printf "\n" a=false while [ $a=true ]; do read i if [ -w $i ] then cat $i | grep stuff > i2 else a=true printf "Oh something is wrong, try again!" sleep 3 fi done 

Odpowiedź

Występują błędy składniowe i logiczne.

$a=true to tylko łańcuch, a NIE operacja porównania. Oddziel spacjami, aby porównanie miało miejsce: "$a" = true.

Po wykonaniu tej czynności pętla w ogóle nie zostanie wprowadzona, ponieważ ustawisz a=false z góry.

POWINIENEŚ w końcu dostać się do pętli, nie będziesz w stanie wyjść, ponieważ a nigdy nie jest ustawione na dowolne inne niż true, ani inny mechanizm wyjścia (np. break).

Odpowiedź

Jak zauważyli inni, w kodzie występują błędy logiczne i składniowe. Witryna ShellCheck jest dobra do usuwania błędów składniowych.

Oto moje podejście. Mam dwie wersje kodu . Pierwsza (co wolę) nie wymaga interakcji z użytkownikiem, ale przyjmuje ścieżkę dostępu w wierszu poleceń. Druga interaktywnie prosi o ścieżkę.

Powód, dla którego pierwsza nie wyświetla interaktywnego monitu o ścieżka jest taka, że nie ma większego znaczenia, jeśli użytkownik skryptu zapisuje ścieżkę w wierszu poleceń lub w wierszu polecenia skryptu, a posiadanie znaku zachęty skryptu do nazwy ścieżki dyskwalifikuje jej użycie np. zadanie cron lub gdziekolwiek indziej, gdzie może nie być podłączony terminal.

#!/bin/sh pathname=$1 if ! grep "pattern" <$pathname >i2; then echo "Something is wrong" >&2 fi 

echo powyżej będzie wykonywane, gdy

  • plik w $pathname nie może zostać odczytany lub
  • plik i2 nie można do niego napisać lub
  • wzorzec nie został znaleziony w $pathname (różni się od twojego kodu, ale patrz poniżej) .

Komunikat o błędzie jest zapisywany jako standardowy błąd, tak jak jest to w zwyczaju w przypadku komunikatów diagnostycznych w ogóle.

Z interaktywnym monitem i opóźnieniem:

#!/bin/bash while true; do read -r -p "Pathname: " pathname if grep "pattern" <$pathname >i2; then break fi echo "Something is wrong" >&2 sleep 3 done 

Tutaj mamy nieskończoną pętlę, która czyta od użytkownika i przerywa pętlę, jeśli wywołanie grep poszło dobrze. Jeśli grep z jakiegoś powodu nie powiodło się (jeden z trzech powyższych powodów), ponownie pojawi się monit o podanie nazwy ścieżki.


Oba fragmenty kodu z osobnymi test na czytelny plik (grep może się nie powieść, nie znajdując niczego lub nie jest w stanie zapisać w swoim pliku wyjściowym.

Najpierw nieinteraktywny wersja:

#!/bin/sh pathname=$1 if [ ! -r "$pathname" ]; then echo "Something is wrong" >&2 fi grep "pattern" <$pathname >i2 

Następnie wersja interaktywna:

#!/bin/bash while true; do read -r -p "Pathname: " pathname if [ -r "$pathname" ]; then grep "pattern" <$pathname >i2 break fi echo "Something is wrong" >&2 sleep 3 done 

Lub wersja interaktywna gdzie pętla zajmuje się tylko wprowadzaniem danych przez użytkownika i walidacją:

#!/bin/bash while true; do read -r -p "Pathname: " pathname [ -r "$pathname" ] && break echo "Something is wrong" >&2 sleep 3 done grep "pattern" <$pathname >i2 

Odpowiedź

Spróbuj użyć prostego przerwania, aby zatrzymać nieskończoną pętlę w następujący sposób:

echo "$(tput setaf 4) Tell me where the file is:" echo # This prints empty line like printf "\n" while true; do # "while true" or "while :" is infinite loop read i if [ -r $i ] # You probably mean -r (readable) and not -w (writable) then cat $i | grep stuff > i2 break # "break" ends loop else echo -n "Oh something is wrong, try again!" # "echo -n" means print without newline character sleep 3 fi done 

Zmodyfikowane miejsca mają komentarze z opisem.

Komentarze

  • grep <$i >i2 zamiast cat. Ponadto w razie potrzeby cytuj rozszerzenia zmiennych, tak jak w teście .

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *