Fórum Ubuntu CZ/SK
Ubuntu pro osobní počítače => Software => Příkazový řádek a programování pro GNU/Linux => Téma založeno: alfonz19 17 Dubna 2009, 20:24:33
-
Zdar,
mám napsanej skript, poslední co zbývá, je vrátit korektní návratovou hodnotu. Netušil jsem jakej to bude problém.
Takže o tom, co mám vrátit se dozvím někde v cyklu, resp. v ifu, který je zanořen ve whilu. Zkoušel jsem uvnitř cyklu volat exit 1 (ale to mi celý skript neukončí), zkoušel jsem nastavit hodnotu proměnné, kterou bych mimo cyklus přečetl s její hodnotou volal exit (ale hodnota nastavená v proměnné uvnitř cyklu se nepřenese mimo cyklus navzdory tomu že tato je deklarována vně cyklu), zkoušel jsem volat uvnitř cyklu exit 1 a mimo cyklus číst $? jestli tam snad nenajdu tu jedničku (ne). Tak a to je asi tak vše co mne napadá.
Takže jak se tato trivialita řeší v bashi???
-
Asi jsem to nepochopil
$ echo "i=0; until [[ i -eq 20 ]]; do let i++; if [[ i -eq 15 ]]; then exit 1; fi; done; echo 'konec'" > /tmp/a
$ /tmp/a
$ echo $?
1
Vložil jsem do cyklu podmínku if a pak exitoval s jedničkou - slovo 'konec' se neobjevilo, protože skript nedojel do konce. Ve výstupu hlásí $? = 1
-
o to horší to je, že tobě to funguje. Bash zatím docela boří moje znalosti a zvyky programování, což mi nedělá dobře.
Takže pošlu příklad skript, je delší, ale důležitých je jen pár posledních řádků kolem ifu. Asi nebude napsán optimálně, ale žádný div. V bashi jsem toho moc nenaprogramoval.
#!/bin/bash
function printUsageAndExit {
echo "Usage: checkFileForWrongIndentation.sh [-v] FILE";
echo;
echo "when swith -v is used then all lines with error is reported, otherwise only report that supplied file is not correct is reported."
exit 1;
}
function testFileExistency {
if [ ! -e "$1" ]; then
printUsageAndExit;
fi
}
LINE_NUMBER=0;
if [ $# -eq 0 -o $# -gt 2 ]; then
printUsageAndExit;
fi
if [ $# -eq 1 ]; then
testFileExistency "$1"
FILE="$1";
VERBOSE=1;
else
#from here on we know, that two parameters were supplied, so we just check for -v switch presence
testFileExistency "$2"
FILE="$2";
if [ "$1" = "-v" ]; then
VERBOSE=0;
else
printUsageAndExit
fi
fi
cat "$FILE" | sed "s/^\([ \t]*\).*$/\"\1\"/" | sed "s/\t//g" | while read LINE; do
#echo "$LINE" | tr -d "\n" | wc -m | tr -d "\n"; echo ": \"$LINE\""
LINE_NUMBER=$(($LINE_NUMBER + 1));
SPACES=`echo -n "$LINE" | wc -m | tr "\n" " "`;
SPACES=$(($SPACES - 2));
if [ $SPACES -gt 3 ]; then
if [ $VERBOSE -eq 0 ]; then
echo "wrong indentation in file \"$FILE\" on line $LINE_NUMBER";
ERROR_FOUND=1;
else
echo "File $FILE has badly indented lines";
echo trying to quit;
exit 1;
echo failed;
#break;
fi
fi
done;
echo hmm
výstup:
File testingDir/SecurityUtil.java has badly indented lines
trying to quit
hmm
komentář: testingDir/SecurityUtil.java je soubor, který byl specifikován jako parametr. Je vidět, že exit skutečně něco udělal protože "failed" se nevypsalo, ale ZJEVNĚ nezpůsobil ukončení skriptu protože se vypíše "hmm" a protože se "hmm" vypíše korektně, pak je $? roven nule. Co je však zajímavější je to, že exit skutečně nastaví $? na 1, protože když výpis "hmm" zakomentuji, dostanu po provedení skritpu v $? jedničku. Proč tedy toto chování? Jaká je příčina, že tvůj exit ukončí skript a můj exist ne?
A jak je to s těmi proměnnými? Skutečně, když jsem v místě kde je teď exit (ten v cyklu) nastavil hodnotu nějaké proměnné, pak v místě výpisu "hmm" měla původní hodnotu - vypadá to, jako kdyby cyklus byl implemen uvnitř nějaké metody a veškeré parametry se mu předávají hodnotou (nemyslím paskalovskou "hodnotou", která je ve skutečnosti "hodnotou-výsledkem")
-
skript testuje, zdali není některý řádek ve zdrojácích odsazen 4 mezerami namísto jednoho tabulátoru, takže pokud bys to chtěl otestovat, tak příklad selhávajícího souboru je například:
this line is ok
this line is not ok
\t this line is not ok either(substitute \t, I can't write tab symbol here.)
-
Problém je v tom, že když "pipneš" výstup do while/until cyklu, spustí se child process s tímto cyklem, takže potom ten exit pouze ukončí ten child process, ne celý skript. Proto se tedy po done objeví ten nápis hmm.
Je to dokonce ještě horší: když si (při tomto způsobu použití) uprostřed toho cyklu nadefinuješ nějakou proměnnou, bash ji po výstupu z něho "zapomene".
V tomto případě by ale mělo stačit po ukončení cyklu testovat $? na návratovou hodnotu, jestli je -eq 1.
Snad jsem to vysvětlil srozumitelně. Viz také třeba
http://www.linuxprogrammingblog.com/pipe-in-bash-can-be-a-trap
http://ubuntuforums.org/showthread.php?t=312017