Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: webhope 31. 03. 2010, 19:49:16

Název: Select a cyclus do ... done
Přispěvatel: webhope 31. 03. 2010, 19:49:16
Pokouším se zjistit jestli je možné udělat následující:

V prvním příkladu, který funguje mám strukturu příkazů takovouto:
Kód: [Vybrat]
select polozka in A B C; do prikazova_cast; done;
Čili vyberu si něco ze seznamu a pak se provede cyklus s příkazy. Tohle mohu opakovat libovolně-krát, protože je to uvnitř while cyklu, a když chci skončit, tak ukončím cyklus while.

A teď mám druhou situaci.
Příkazová část uvnitř do.. done; zůstává skoro stejná, až na to, že vše chci provést automaticky, místo ručně. Nechci ale kopírovat dlouhý příkazový blok, raději bych použil stejný cyklus. Problém je v tom, že se potřebuji v této situaci zbavit toho selectu.

Zkoušel jsem něco takového, ale asi to nemá správnou syntaxi:
Kód: [Vybrat]
automate=0
# automate=1

echo; echo 'Vyberte';

if [ "$automate" == "0" ]; then
  select hledam in 'A' 'B' 'C';
fi;
do
  echo $automate
  break;
done;


Výsledek:

Kód: [Vybrat]
# if [ "$automate" == "0" ]; then
>   select hledam in 'A' 'B' 'C';
> fi;
bash: chyba syntaxe poblíž neočekávaného tokenu „fi“
# do
bash: chyba syntaxe poblíž neočekávaného tokenu „do“
#   echo $automate
0
#   break;
bash: break: má smysl jen ve smyčkách „for“, „while“ nebo „until“
# done;
bash: chyba syntaxe poblíž neočekávaného tokenu „done“
Název: Re: select a cyclus do ... done
Přispěvatel: webhope 01. 04. 2010, 18:57:46
Ještě jsem zkoušel tohle řešení (předdefinovat vstup pro select), ale buď to dělám blbě nebo to nejde:

Kód: [Vybrat]
i=$((i+1));
( [ "$automate" == "0" ] && select item in 'A' 'B' 'C'  <$i ) || ( [ "$automate" == "1" ] && select item in 'A' 'B' 'C' );
do
echo $automate
break
Název: Re: select a cyclus do ... done
Přispěvatel: deadmail 01. 04. 2010, 20:26:11
Citace
Nechci ale kopírovat dlouhý příkazový blok

Na to sa pouzivaju funkcie
Kód: [Vybrat]
function OpakujuciSaCyklus {
#opakujuci sa kod
}

if [ "$automate" -eq 0 ]
then
   select a in A B C
   do
     OpakujuciSaCyklus
   done
else
   OpakujuciSaCyklus
fi
Název: Re: select a cyclus do ... done
Přispěvatel: webhope 01. 04. 2010, 23:22:09
Pomocí funkce bych to řešit uměl, ale jde o to, že předělávat několik příkazových bloků a dalších cyklů do funkce se mi nezdá efektivní ani dost přehledné. Bylo by to dost náročné předělat to celé do funkce. Jednodušší řešení asi bude pro mě pouze částečná automatizace.

Při podmínce pokud je pravda, přepíšu pole pro výběr např.
Kód: [Vybrat]
select item in "Opravdu zpracovat tuto položku?" "Ne"Přitom původní pole obsahuje delší seznam. Zde při tom zautomatizování použiju i=$((i+1)) abych získal z předdefinovaného pole aktuální položku. Takže zpracuju celé pole (všechny položky) uvnitř cyklu while, uživatel ale bude muset potvrdit nebo odmítnout cca 18 položek.
Název: Re: Select a cyclus do ... done
Přispěvatel: . 02. 04. 2010, 04:00:54
Pak nemusíš psát funkci pro tělo toho cyklu, ale pro jeho podmínku.
Kód: [Vybrat]
function getdalsi { dalsi=automaticky vyber nebo select}
while getdalsi; do ...
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 02. 04. 2010, 13:40:14
To nevím jak to myslíš. Moc stručné. Nepochopil jsem zpracování argumentů funkce a kde má být done;
Název: Re: Select a cyclus do ... done
Přispěvatel: . 02. 04. 2010, 19:24:33
Myslel jsem tím to, že ten select ...; do ...; done můžeš jednoduše upravit třeba na while funkce ...; do ...; done a dopsat jen drobnou funkci, která podle potřeby vybere selectem nebo automaticky.
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 03. 04. 2010, 18:16:35
Jediné co mě napadlo je toto:

Kód: [Vybrat]
test(){ if [ "$automate" == "1" ]; then  return true; else return false; fi; }
i=$((i+1));
test() ||  select item in 'A' 'B' 'C'  ;
do
echo $automate
break
done;

Mělo by to dělat toto.
Pokud je $automate==1, tak se provede funkce a vrátí true, takže select se přeskočí, ale cyklus se provede.
Pokud je $automate==0, tak se provede funkce a vrátí false, takže select se provede a cyklus se provede.

Hlásí to stejnou chybu:
bash: chyba syntaxe poblíž neočekávaného tokenu „||“

Hlavní pro mě je, abych ty bloky v cyklu nemusel strkat do funkce. V prvním případě se select nemá provést, ve druhém ano.
Název: Re: Select a cyclus do ... done
Přispěvatel: woz 03. 04. 2010, 20:44:27
Neviem či som vás správne pochopil ale mohli by ste si buď spraviť vlastný "select" alebo, za predpokladu že skupina príkazov prikazova_cast pracuje buď z defaultnou hodnotou a je vynechany užívateľský vstup ( automate=1 ) alebo z hodnotou vybratou užívateľom ( automate=0 ) by to mozno islo aj takto:
Kód: [Vybrat]
REP="default value"

if [ "$AUTOMATE" == "0" ]; then
    select item in 'A' 'B' 'C' ; do
        REP=$item
        break
    done
fi

echo $REP
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 04. 04. 2010, 09:26:43
Ale měl jsem chybnou syntaxi v tom starém kodu proto, mi to nefungovalo. Kód dole funguje, ale musím ještě vymyslet, jak dořešit, aby cyklus fungoval i při volání té funkce test (select=0)! Asi nemohou rekurzivně volat test a při tom spouštět cyklus...

Poznámka: přejmenoval jsem název proměnné $automate na $select. Pokud je $select==1 použije se select a spustí cyklus. Pokud je $select==0 spustí se cyklus, aniž by se aktivoval select.

Kód: [Vybrat]
test(){
if [ "$select" == "1" ]; then  return 1; else return 0; fi;
}

select=0;
pole=('A' 'B' 'C')
i=$((i+1));
test ||  select item in "${pole[@]}";
do
echo $i
done;

EDIT:
No jo, jenže největší problém je v tom, že ten cyklus do.. while je nejspíš součástí toho select. Asi jako if [...]; then ...; fi; Čili, ten cyklus patří k tomu selectu, ne k té funkce test. Když na začátku podmínky s testem vyjde, že nemá provádět select, tak neprovede ani ten cyklus. Čili řešení situace nevidím.

Název: Re: Select a cyclus do ... done
Přispěvatel: deadmail 04. 04. 2010, 10:08:28
Ak som spravne pochopil myslienku, tak by to mohlo vyzerat takto:

Kód: [Vybrat]
function test {
 if [ "$1" == "N" ]
 then
  if [ -z "$volba" ]
  then
   volba="automation"
   return 0
  else
   return 1
  fi
 fi
 PS3="Vyber si (zly vyber ukonci cyklus): "
 select volba in A B C
 do
  [ -z "$volba" ] && return 1 || return 0
 done
}

selection="N"; #"Y"

volba=""
while test $selection
do
 echo "Vybrate: $volba"
done

Ak je v premennej selection retazec "N", tak sa raz spusti cyklus a premenna volba obsahuje "automation". Inak sa spusti cyklus podla vyberu zo selectu. Zly vyber v selecte ukonci cely cyklus while.
Název: Re: Select a cyclus do ... done
Přispěvatel: deadmail 06. 04. 2010, 16:04:26
Ta ista otazka sa nepise do dvoch roznych tem (http://forum.root.cz/index.php?topic=307.msg1351#msg1351)!!!
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 07. 04. 2010, 13:41:45
Tak jsem aplikoval celou strukturu jak si doporučil a už to funguje až na jednu poslední věc:

Kód: [Vybrat]
while get_device || [ "$continue" == "1" ] ; do # Funkce "get_device $automate" rozhoduje o tom zda se provede select
echo ; echo POKRACOVANI:$continue; echo
done;

Funkci jsem pojmenoval get_device.
Když se zpravují všechna zařízení, tak vracím (oprava: nastavuji) continue=0; přesto se ale cyklus neukončí a je tam výstup:
POKRACOVANI:0

Takže zkouším [[ "$continue" == "1" ]] a [[ $continue -eq 1 ]] ale výraz je vyhodnocen pozitivně. Takže si v klidu pokračuje dál  :-(

Edit:
Jo a funkce vraci 0.
Název: Re: Select a cyclus do ... done
Přispěvatel: deadmail 07. 04. 2010, 14:39:11
Citace
tak vracím continue=0

Co si ty myslel? Kde sa nastavuje premenna continue?? Funkcia vracia hodnotu pomocou return, spracuje sa len cez nazov funkcie (zavola ju a vrati vysledok).

Cyklus bude pokracovat ak get_device vrati nenulovu hodnotu alebo continue je jedna. Nechcel si tam mozno "a zaroven" namiesto "alebo"?
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 07. 04. 2010, 15:03:42
Nesprávně jsem se vyjádřil. Ve funkci nastavuji proměnnou continue.

Funguje to takto:
V té funkci zpracovávám pole - seznam zařízení a přípojných bodů.
Počítám cykly. Dokud se nejedná o poslední cyklus $i==$count tak se nastavuje continue=1 a funkce vrací 1. Když je počet cyklů $i==$count tak nastavuji continue=0 a vracím 0;

Teď nevím proč to tak, je ale jinak to nešlo, je to složitější s těma cyklama. Každopádně, stoprocentně vím, že funkce mi u poslední položky nastavuje continue=0. Tudíž by se cyklus už dál neměl provádět. Funkce vrací 0, takže podmínka OR vyhodnocuje další podmínku a ta je 0

Pozn:
Právě že v té funkci jsem si to zkontroloval, že vrací skutečně 0. Dal jsem tam echo "Nejaky text" a tak jsem to vizualne zkontroloval že to funguje správně.
Název: Re: Select a cyclus do ... done
Přispěvatel: deadmail 07. 04. 2010, 15:45:24
Kód: [Vybrat]
while funkcia; do ... done

Cyklus sa opakuje kym funkcia vracia hodnotu 0. Na skoncenie treba vrati 1,vid TLDP (http://tldp.org/LDP/abs/html/loops1.html)
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 07. 04. 2010, 15:50:58
Kód: [Vybrat]
while funkcia; do ... done

Cyklus sa opakuje kym funkcia vracia hodnotu 0. Na skoncenie treba vrati 1,vid TLDP (http://tldp.org/LDP/abs/html/loops1.html)

Aha, já myslel, že to je naopak!
Název: Re: Select a cyclus do ... done
Přispěvatel: deadmail 07. 04. 2010, 19:47:59
Citace
Aha, já myslel, že to je naopak!

nenulova navratova hodnota znamena chybu
Název: Re: Select a cyclus do ... done
Přispěvatel: webhope 08. 04. 2010, 10:43:41
No skvělé. Končeně to funguje.
Dík za pomoc.