szám ellenőrzés

Van egy számozott listám, melyet egy tömbbe rakok.
A tömb végén meghatároztam az utolsó számot.
        max_number=$(( index - 1 ))

A lista:        
01 foo
02 foo
...
89 foo

A bash szkript megkér hogy válasszak egy számot a listából, majd elemzi a választott számot.
        read -r choice
        number_check=$(echo "${choice}" | grep -E '^[0-9]{2}|0')

A 0-ra szükségem van, viszont a többi egyjegyű számok nem kellenek. mivel a lista is kétjegyű. Ezért a regex.
Így két legyet ütök egy csapásra, Ha betűt adok meg, nem fogadja el.
Viszont van egy ilyen ellenőrző is:
    if (( choice > max_number )); then
Lefut ugyan de hibát dob. Ezért elrejtem a hibaüzenetet. Bár jó lenne megoldani.
    if (( choice > max_number )) >/dev/null 2>&1; then
S itt vannak a gondok. 
Próbálkoztam ezzel is:
    if [ ${choice} -gt ${max_number} ]; then
de a 08, 09 oktális decimális keverés miatt hibát dob, amennyiben a 08 vagy a 09-es kerül kiválasztásra.
 

read -r choice
number_check=$(echo "${choice}" | grep -E '^[0-9]{2}|0')            
if [ "${number_check}" != "" ]; then
#     if (( choice > max_number )) >/dev/null 2>&1; then
    if (( choice > max_number )); then                
       clear
    else
        if [ "${choice}" = "0" ]; then
            clear
            exit
        else
            minden rendben
        fi
    fi
else
    clear
fi

Hozzászólások

"if [ ${choice} -gt ${max_number} ]; then

de a 08, 09 oktális decimális keverés miatt hibát dob, amennyiben a 08 vagy a 09-es kerül kiválasztásra."

Kolumbusz tojása: if [ 1${choice} -gt 1${max_number} ]; then

Ha "1" helyett "10#" amit eléfűzöl, akkor a kód olvashatóbb (pontosan azt írod le, amire gondolsz, nevezetesen hogy 10-es számrendszerben értendő; nem kell tippelgetni hogy vajon mire gondolt a költő) és robusztusabb (működik akkor is, ha nem azonos hosszúak a számok).

IMHO megvan a helye a Kolumbusz tojása típusú megoldásoknak is, de nem ott, ahol a rendes megoldás semmivel sem bonyolultabb.

Mondjuk nekem egy ilyen script nem dob hibát:

 for i in $(seq -w 5 10); do echo $i; if [ ${i} -gt 6 ] ; then echo nagyobb; fi; done

de ha berakok egy echo $((i)) -t, akkor az már igen...

Shell: GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

[kroozo@superior tmp]$ cat t1.sh 
#!/bin/bash

for i in $(seq -w 5 10); do echo $i; if [ ${i} -gt 6 ] ; then echo nagyobb; fi; done
[kroozo@superior tmp]$ ./t1.sh 
05
06
07
nagyobb
08
nagyobb
09
nagyobb
10
nagyobb
[kroozo@superior tmp]$ cat t2.sh 
#!/bin/bash

for i in $(seq -w 5 10); do echo $((i)); if [ ${i} -gt 6 ] ; then echo nagyobb; fi; done
[kroozo@superior tmp]$ ./t2.sh 
5
6
7
nagyobb
./t2.sh: line 3: 08: value too great for base (error token is "08")
[kroozo@superior tmp]$ bash --version
GNU bash, version 5.2.15(1)-release (x86_64-redhat-linux-gnu)

Zellertől megkérdeztem, hogy hol ad hibát a $((i)). Erre krozoo adott 2 scriptet, amiben megmutatta, hol rossz. Én megmagyaráztam, miért rossz. Erre rákérdezni, hogy ez hogy kerül ide - no itt én elvesztem.

Szerintem egyszerűbb lenne case-zel vizsgálni az inputot, tud regexet, így az if előtti grep sem kell, az sem probléma ha üres vagy nincs szám.

"Sose a gép a hülye."

"case-zel vizsgálni az inputot, tud regexet"

Nem, a shell nem tud regexp-et, hanem pattern-t tud (amit a fákjlnév megadásánál lehet használni). Pontosabban ma már a shell is tud regexp-et, de amennyire tudom, egyedül a [[ nevű ]] parancsban, ha a =~ operátort használod. De a case-ben nem.

ez?

#!/bin/bash

case $1 in
   [123456789])
       echo szam
       ;;
    [abc])
       echo betu
       ;;
   0)
       echo nulla
       ;;
   "")
       echo semmi
       ;;
   *)
       echo default
       ;;
esac
 

"Sose a gép a hülye."

Ez pontosan az a pattern, amit írtam. Mi sem bizonyítja jobban, mint a legutolsó ág * mintája. Regexp esetén ugyanis a * előtt kell valaminek állnia, és a * előtt álló "izé" 0, 1, 2, vagy többszöri előfordulását jelenti. Pl: [a-z]* - tetszőleges számú (0 is lehet) kisbetű. [0-9]* - számjegyek sorozata. Míg a patternként a * önmagában azt jelenti, hogy bármilyen hosszúságban bármi. Ha azt írom a*b, akkor ha ez regexp, akkor 0 vagy több kis a, amit egy db. kis b követ, azaz extrém esetben : b, vagy ab, aab, aaab, ...., aaaaaaaab. De az aaaaabbbb -ből csak az első b-ig jelenti a mintát. (*) Ha ugyanez patternként van értve, akkor kis a és kis b, amik között BÁRMI lehet: ab, aXb, aaaaaaXYZ123456b, sőt aaaabbbbbbbb, és az összes b-t is jelenti.

Azt elismerem, hogy kurva zavaró, hogy a [...] és a * mind pattern-ben, mind regexp-ben szerepelhet, de nem egészen ugyanazt jelentik. Shell-ben (és a fájlnév megadás utáni leggyakoribb előfordulás a "case" parancs) patterneket lehet használni. Egy csomó egyéb szoftvernél meg regexpeket - amik teljesen másként működnek.

(*) a linuxos grep-nél ugye van, hogy színekkel kiemeli, hogy mi az, amire a minta (regexp) illeszkedik. Így lehet ellenőrizni ezt, amit mondtam az aaabbbb és az a*b kapcsán.

Nekem is a select volt az első gondolatom, de a select maga generálja a számozott listát, itt meg eleve van egy (láthatóan máshogy) számozott lista.

Én pedig mindig örülök, amikor rájövök, hogy a shell script még  mindig mennyi mindenre jó - igaz nem árt hozzá a nyelvet jól ismerni, és a megfelelő eszközeit használni a script megírásakor. (Tipikus példa a tipikus linuxizm / bashizm: for i in `seq 1 100` - az ilyesmire a while / until ciklus való, de ha valaki mindenáron for-t akar, akkor írjon for i in {1..100} -at.)

1. Ne generálja magának a számokat, teljesen felesleges.

2. Hát igen, már ha lenne nyelv, csak az épp nincs :P A dolgok nagy részét a rendszeren rendelkezésre álló parancsokból kell kisakkozni (amik vagy telepítve vannak, vagy nem), amikből a GNU implementáció elég sokszor eltér a *BSD implementációtól (embedded/egyéb rendszerekről nem is beszélve). Típusok sem igazán vannak, általában a szövegeket kell parse-olni stdout-ról (ha épp nem csúszik át stderr-re), viszont regex támogatás az nincs. De egyébként a tömbök is csak bash 3(?)-tól vannak, asszociatív tömbök csak valami külső paranccsal...

1.

"Van egy számozott listám".

Nekem ebból az jön le, hogy ez valahonnan máshonnan van

2.

Érteni értem, de pont azt mondom, hogy ismerni kell a rendszert, és úgy lehet - igen szovegmatató eszközökkel - eredményt elérni. A GNU vs *BSD implementációk problémakörét pont jól lefedi a POSIX, 35-40 éve ugatom, hogy arra kéne lőni. Nem tudom mióta van a bash-ban tömb, a Korn-shell aminek ksh88 nevű verziója már k régen elavult, már' 88-ban tudta, szóval az nem komoly probléma. A ksh93-ban pedig - igen., '93-ban - már volt asszociatív tömb :-) Ráadásul az awk - ami eléggé alap UNIX / POSIX eszköz, a 77-es verziójában tudtommal már szintén tudta, de a 88-as már garantáltan. Azaz teljesen igaza volt Larry Wall-nak, aki a "van awk 2 perl, meg sed 2 perl, miért nincs shell 2 perl" kérdésre azt válaszolta, hogy a shell-scriptek legtöbbször egy kis sed / cut / cat / tr / join, stb összeragasztására jók - nos ezt jelenti a shell program írása. Más kérdés, hogy ha az ember hajlandó megtanulni a (z igenis létező) nyelv eszköztárát, sok esetben fentieket nem feltétlenül (de jó pár esetben) 100%-ban hanyagolhatják. Akinek meg nem tetszik, tanulja meg az AWK-ot, "perl-t, vagy a ma divatos scriptnyelvek bármelyikét - de legalább a shell *alapjait* tanulja meg tisztességesen. De amíg a többség már az aposztróf vs idézőjel dolgot nem képes megtanulni, vagy hogy "minden változóhivatkozást idézőjelek közé zárunk (kivéve azt a 2 esetet amikor pont nem)" - no addig ne csodálkozzunk azon, hogy szar shell-scriptek ömlenek mindenhonnan. Szóval aki nem ismeri, az undorodhat tőle, de az ő szava szerintem keveset nyom a latban.

(A powershell jobb?)

"kivéve azt a 2 esetet amikor pont nem" - taníts, mester :-) Lehet, hogy tudom, csak nem tudom, hogy tudom :)

A powershell van, amiben jobb. A nem bájtok sorozata, hanem objektum "közlekedik" a csőben sokszor egyszerűsíti az életet (másjor meg nem...), de ahogy mondani szoktam, feladathoz az eszközt.

1.

a V változóban gyüjtesz dolgokat (V="$V x"  stílusban), majd a benne levő szavakat szeretnéd külön-külön kezelni:

for i in $V ; do .. done

Itt nagyon rossz lenne a "$V" forma.

2.

if Z ; then

CMD_X="commandX --nondefoption"

else

CMD_X="cmdX --compat"

fi

$CMD_X param1 param2

Ha a futtatási sorban idézőjelbe teszed, akkor lesz meglepetés, hogy miért van c-n-f a 'cmdX --compat' nevű parancsra. (A shell hibaüzenetben persze nem idézőjelek / aposztrófok közt írja ki.) Ezt a formát nagyon régóta alkalmazzák az egymással csak kicsit kompatibilis rendszereken futtatható kódok írására.

Értem, hogy megvan a megoldás, de meg tudnád mutatni azt, ahol az a if (( .. )) hibát dob? Meg pl. azt, hogy mi a hozzá tartozó input - amitől hibaüzenetet generál.. Csak mert szerintem pl. már ez se jó:

number_check=$(echo "${choice}" | grep -E '^[0-9]{2}|0')  

Ha a grep minta végére raknál egy $-jelet, akkor még csak érteném, de így 12v -t szó nélkül benyeli - majd ez után tényleg kapok egy hibát. Vagy ha a grep-nek odaadnád a -o opciót, hogy csak a mintára illeszkedő eredményt írja ki, ne a teljes sort, ahol van illeszkedés.

A grep megoldás is jó,( bár nem a legszebb). Viszont ha maradsz regex vonalon, akkor ez csak a számokat hozza ki.

Mivel nem volt tiszta, hogy a 0[1-9]-re is akarsz-e egyezést, ezért ez most az alábbi számokra mutat egyezést. 

0, 1-9,10 felett

Nem fog egyezni a 00-val és a 0[1-9]-el.

Remélem jól értettem a kérdést.

https://regex101.com/r/syp3YU/1