Szeretném, ha a felhasználó megkérdezne egy kérdést, majd megadná a választ, amelyet egy i nevű változó alatt tárolnak, majd ha a válasz (amely egy fájl) létezik és írható, elolvassa, felkapja a fájlban lévő dolgokat, és ezeket egy újba írja. Ha a fájl nem létezik, vagy a felhasználónak nincs elegendő jogosultsága a fájl felett, akkor figyelmeztetés jelenik meg, a program 3 másodpercig alszik, és a ciklusok újra indulnak. Miért nem működik? A figyelmeztetés egyszerűen nem tűnik el, és a hurok sem fog folytatódni.
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
Válasz
Szintaxis és logikai hibái vannak.
A $a=true
csak egy karakterlánc, NEM összehasonlító művelet. Szétválasztva szóközökkel, így az összehasonlítás megtörténik: "$a" = true
.
Ezzel a művelettel a hurok egyáltalán nem lesz megadva, ahogy beállítja a a=false
előre.
KELL, hogy végre bekerülj a ciklusba, nem fogsz tudni kilépni, mivel a
soha semmire nincs beállítva, csak true
, és nincs más kilépési mechanizmus (pl. break
).
Válasz
Amint mások rámutattak, logikai hibák és szintaxis hibák vannak a kódban. A ShellCheck webhely jó a szintaktikai hibák kiküszöbölésére.
Itt állok ezzel kapcsolatban. A kódnak két verziója van . Az elsőnek (amelyet én jobban szeretek) nincs felhasználói interakció, de egy útvonalnevet vesz fel a parancssorba. A második interaktívan kér útvonalnevet.
Az ok, amiért az első nem interaktívan kéri a Az útnév az, hogy alig van különbség, ha a szkript felhasználója írja be az útvonalnevet a parancssorba vagy a parancsfájl parancsára, és ha a parancsfájl parancssor megadja az útvonal nevét, kizárja, hogy pl. egy cron-feladat vagy bárhol máshol, ahol nem csatlakozik terminál.
#!/bin/sh pathname=$1 if ! grep "pattern" <$pathname >i2; then echo "Something is wrong" >&2 fi
A fenti echo
akkor kerül végrehajtásra, ha
- a
$pathname
fájl nem olvasható, vagy - a nem írható, vagy
- a minta nem található a
$pathname
helyen (ez eltér a kódodtól, de lásd alább) .
A hibaüzenet szabványos hibára van írva, mint általában a diagnosztikai üzeneteknél.
Interaktív felszólítással és késleltetéssel:
#!/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
Itt van egy végtelen ciklusunk, amely olvasható a felhasználótól és kitör a ciklusból, ha az grep
hívás rendben van. Ha a grep
bármilyen okból meghiúsult (a fenti három ok egyike), akkor az útvonalnév újra kéri.
Mindkét kódrész külön-külön teszt egy olvasható fájlra (a grep
meghiúsulhat, ha nem talál semmit, vagy nem tud írni a kimeneti fájljába.
Először a nem interaktív verzió:
#!/bin/sh pathname=$1 if [ ! -r "$pathname" ]; then echo "Something is wrong" >&2 fi grep "pattern" <$pathname >i2
Ezután az interaktív verzió:
#!/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
Vagy egy interaktív változat ahol a hurok csak a felhasználó bevitelével és érvényesítésével foglalkozik:
#!/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
Válasz
Próbáld meg egyszerűen a break segítségével megállítani az ilyen végtelen ciklust:
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
A módosított helyekhez megjegyzéseket fűznek leírással.
grep <$i >i2
, nem pedig azcat
. Idézze meg a változó bővítéseit is, ahol szükséges, például a tesztben .