Cum buclez o instrucțiune if în bash?

Vreau ca utilizatorul să fie solicitat cu o întrebare și apoi să furnizeze răspunsul, care va fi stocat sub o variabilă numită i, apoi dacă răspunsul (care este un fișier) există și se poate scrie, îl citește și agită lucrurile din fișier și scrie aceste lucruri într-unul nou. Dacă fișierul nu există sau utilizatorul nu are suficiente permisiuni pentru fișierul respectiv, atunci se va solicita un avertisment, programul va dormi 3 secunde și buclele vor începe din nou. De ce nu funcționează? Avertismentul pur și simplu nu va dispărea, nici bucla nu va continua.

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 

Răspuns

Aveți erori de sintaxă și logice.

$a=true este doar un șir, NU o operațiune de comparație. Separați-vă cu spații, astfel încât comparația să aibă loc: "$a" = true.

Cu acea funcționare, bucla câștigată nu va fi introdusă deloc, pe măsură ce setați a=false în avans.

TREBUIE să intri în buclă, nu vei putea ieși, deoarece a nu este niciodată setat la orice altceva decât true și nici nu este prevăzut un alt mecanism de ieșire (de ex. break).

Răspuns

După cum au subliniat alții, aveți erori logice și erori de sintaxă în cod. site-ul ShellCheck este bun pentru eliminarea erorilor de sintaxă.

Iată ideea mea. Am două versiuni ale codului . Primul (pe care îl prefer) nu are interacțiune cu utilizatorul, dar ia un nume de cale pe linia de comandă. Al doilea cere interactiv un nume de cale.

Motivul pentru care primul nu solicită interactiv un calea este că nu prea are nicio diferență dacă utilizatorul scriptului scrie calea pe linia de comandă sau la promptul scriptului dvs. și dacă solicitarea scriptului pentru calea respectivă o descalifică din a fi utilizată de ex. un job cron sau oriunde altundeva unde este posibil să nu existe un terminal atașat.

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

echo de mai sus va fi executat când

  • fișierul din $pathname nu poate fi citit sau
  • fișierul i2 nu se poate scrie sau
  • modelul nu a fost găsit în $pathname (acest lucru este diferit de codul dvs., dar vedeți mai jos) .

Mesajul de eroare este scris în eroare standard, așa cum este obișnuit cu mesajele de diagnosticare în general.

Cu solicitare interactivă și întârziere:

#!/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 

Aici avem o buclă infinită care citește de la utilizator și iese din buclă dacă apelul grep a mers bine. Dacă grep a eșuat din orice motiv (unul dintre cele trei motive de mai sus), calea este solicitată din nou.


Ambele bucăți de cod cu o separare test pentru un fișier lizibil (grep este permis să eșueze prin faptul că nu găsește nimic sau nu poate scrie în fișierul său de ieșire.

Mai întâi, fișierul non-interactiv versiune:

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

Apoi versiunea interactivă:

#!/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 

Sau, o versiune interactivă unde bucla se referă doar la introducerea și validarea utilizatorului:

#!/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 

Răspuns

Încercați să utilizați pur și simplu pauză pentru a opri o buclă infinită astfel:

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 

Locurile modificate au comentarii cu descriere.

Comentarii

  • grep <$i >i2 mai degrabă decât cat. De asemenea, citați extensiile variabile acolo unde este necesar, ca în test .

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *