Select a cyclus do ... done

webhope

Select a cyclus do ... done
« kdy: 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“
« Poslední změna: 01. 04. 2010, 23:27:55 od Petr Krčmář »


webhope

Re: select a cyclus do ... done
« Odpověď #1 kdy: 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

deadmail

Re: select a cyclus do ... done
« Odpověď #2 kdy: 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

webhope

Re: select a cyclus do ... done
« Odpověď #3 kdy: 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.
« Poslední změna: 02. 04. 2010, 10:13:02 od webhope webhope »

.

Re: Select a cyclus do ... done
« Odpověď #4 kdy: 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 ...


webhope

Re: Select a cyclus do ... done
« Odpověď #5 kdy: 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;

.

Re: Select a cyclus do ... done
« Odpověď #6 kdy: 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.

webhope

Re: Select a cyclus do ... done
« Odpověď #7 kdy: 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.
« Poslední změna: 03. 04. 2010, 18:18:40 od webhope webhope »

woz

Re: Select a cyclus do ... done
« Odpověď #8 kdy: 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

webhope

Re: Select a cyclus do ... done
« Odpověď #9 kdy: 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.

« Poslední změna: 04. 04. 2010, 09:43:29 od webhope webhope »

deadmail

Re: Select a cyclus do ... done
« Odpověď #10 kdy: 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.

deadmail

Re: Select a cyclus do ... done
« Odpověď #11 kdy: 06. 04. 2010, 16:04:26 »
Ta ista otazka sa nepise do dvoch roznych tem!!!

webhope

Re: Select a cyclus do ... done
« Odpověď #12 kdy: 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.
« Poslední změna: 07. 04. 2010, 15:04:21 od webhope webhope »

deadmail

Re: Select a cyclus do ... done
« Odpověď #13 kdy: 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"?

webhope

Re: Select a cyclus do ... done
« Odpověď #14 kdy: 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ě.
« Poslední změna: 07. 04. 2010, 15:07:09 od webhope webhope »