november 22, 2015

Pakkfailide feilimisest II














Selles, kindlalt pakkfailide käsitlemise viimses osas ma üritan näidata, 
 et on äärmiselt halb plaan üldse .cmd  või .bat faile kusagilgi kasutada.
 Jäägu see minu jutt pakkfailidest (koos käesoleva osaga) vaid ajalooliseks illustratsiooniks.
 Mõningane tutvus PowerShelliga viitab sellele, et mingi väljapääs on skriptimisel sellele
 keelele üle minna, nii nagu Windows keskkonna programmeerijatelgi ei ole pääsu C#-st. Ehk olen siin liialt skeptiline.

 I Kuidas väljastada "&" sisaldavaid teateid ilma kõvaketast formattimata

 Olgu meil selline programm: 

@ECHO OFF
SET "teade=date & time on DOS käsud kuupäeva ja kellaaja muutmiseks!"
echo %teade%

Üllatus, üllatus saate ekraanile

date
The system cannot accept the time entered.
Enter the new time:

ja peate sisestama (võite selle küll ära jätta) uue aja.
Kui echo %teade% 
on suunatud kuhugi faili, näiteks
echo %teade%>>teated
tulevad ekraanile saladuslikud 2 rida 
date 

ja kasutaja ei saagi teada,
et hooletu (või kergeusklik) programmeerija laseb tal oma arvuti aega sisestada.
Pärast enterit leitakse aga logi või teadeta failis täiesti arusamatu jura -

The system cannot accept the time entered.
Enter the new time:

& järel saab muidugi olla suvaline sõne, mida DOS püüab täita.
Näiteks 
del oluline.txt

Samasugune ebameeldiv üllatus ootab meid & sisaldava muutuja sisu kopeerimisel, kui programmeerija on unustanud jutmärgid.

@ECHO OFF
SET "teade=date & time on DOS käsud kuupäeva ja kellaaja muutmiseks!"
SET var=%teade%

Jälle üritatakse käima tõmmata käsku time. 
Võib proovida neid koodijupikesi käivitada kas SETLOCAL enableDelayedExpansion
või disableDelayedExpansion olekutes, vahet ei tule.

(kes ei tea mis need on ja ikka huvitub, vaadaku minu eelmist juttu pakkfailidest või manuaale mujalt)

See pornograafia peaks olema välistatud, seetõttu ei saa mistahes väljastust 
käsu 
echo %var% 
abil pidada vastuvõetavaks.

SET omistusel õnneks päästavad jutumärgid kõige hullemast - ampersandi järel tulevat
ei tõmmata vähemalt käima.
Muuseas, ka echo "%var%" puhul pääsete vaid tülikate väljundit risustavate jutumärkidega.
Aga mitte alati ei ole väljundi puhul võimalik talitada vastavalt meeleolule, väljund peab sisaldama teatud 
kindlaid asju ja mitte näiteks jutumärke.

Sellest olukorrast võiks päästa vaid 
SETLOCAL enableDelayedExpansion kasutamine.
Kõik väljastused võiksid toimuda echo !var! 
kujul, ümberomistused 
SET "var1=!var2!" 
kujul, kasutades alati
ohutuse mõttes ümbrisena jutumärke. 

II Kuidas lugeda andmeid sisse ilma kadudeta

Soovitus omistada enableDelayedExpansion sisselülitatud olekus ainult ! ! märke kasutades on väga oluline:
Protsendimärkidega omistuse 
SET "var1=%var2%"
korral jääte hüüumärkidest ja hüüumärkide vahel olevast lihtsalt ilma või mis veel hullem,
kui teil on selline programne muutuja, siis hüüumärkide vahel olev asendatakse selle sisuga.
Selleks, et seda näitena demonstreerida, peab ära õppima programmi sees olevate tekstiomistuste korral 
paosümbolid, et pääseda juba esimesel omistusel teksti interpoleerimisest.
% märgi peab asendama %% -ga ja hüüumärgi ^! -ga.

Näide:

@ECHO OFF
SETLOCAL enableExtensions enableDelayedExpansion
SET "teade=kvartali %kasum% oli 5%% (protsenti)jasiis6%%. ^!Hiilgav^!!" 
SET "hiilgav=masendav"
SET teade
SET "var=%teade%"
SET var
EXIT /B 0

Sõnejupist  %kasum% teate sees olete juba enne muutujateni jõudmist ilma.
var-s on omistamise tagajärjel kadunud teates sisalduvad hüüumärgid ja "hiilgav" on asenunud "masendav" -ga.

enableDelayedExpansion osutub siiski väga mürgiseks õunaks.
Selgub, et ei ole võimalik kuidagi lugeda tekstifaili sisu ilma kadudeta muutujatesse selles programses olekus.

Ainukeseks viisiks DOS-s failide sisu programselt vaadelda on for tsükkel.

Kõigepealt peab ära lahendama for tsükli tühjade ridade probleemi, mida for tsükkel ignoreerib.
Selleks on siiski toimiv, aga hädine lahendus find 
käsu näol.

find /v /n "" teated.txt >teated1.txt  

tekitab teated.txt failist teated1.txt faili, kus 2 esimest rida on spämm, mille saab ära koristada ning ülejäänutele on ees nurksulgudes rea numbrid.
Järgmises ringis tuleks need nurksulgudes olevad reanumbrid ära koristada ja uurida selle taga olevaid tekstiridu, kusjuures ka tühjad read on analüüsitavad.

Olgu näiteks meil selline 
teated.txt fail:

date & time on !DOS! %DOS% korraldused aja muutmiseks!
tere %tere%  !tere!!!!
ja nii edasi ja edasi ...

tavaliseks echo testiks aga sobib selline programm:

@ECHO OFF
SETLOCAL enableExtensions enableDelayedExpansion
find /v /n "" teated.txt >teated1.txt
for /f "tokens=1,* skip=2 delims=[]" %%a IN (teated1.txt) do (
set "var=%%b"
set var
echo %%b
)
PAUSE
EXIT /B 0

Tulem aga on kurvastav  

var=date & time on  %DOS% korraldused aja muutmiseks
date & time on  %DOS% korraldused aja muutmiseks
var=tere %tere%
tere %tere%
var=ja nii edasi ja edasi ...
ja nii edasi ja edasi ...

juba %%b sisus on enableDelayedExpansion korral
kadunud ! ! vahel olevad sõned koos hüüumärkidega.
Juba esimesel sisselugemisel hakatakes faili ridasid intepoleerima, üritades 
! ! vahel olevaid
sõnesid asendada muutujatega.
Me ei saa iialgi teada, kas failis oli midagi hüümärkide vahel või ei olnud.

Üllatus, üllatus: 
disableDelayedExpansion seda tempu ei tee - asendage see koht programmis
(ja saate lõpuks valmis DOS programmi, mis faili sisu rida realt viisakalt kopeerib:)

Nõiaring - et sisendandmeid kätte saada, tuleb kasutada disableDelayedExpansion seisundit, 
et väljastada, enableDelayedExpansion seisundit. 
(echo näiteprogrammis me ei tee andmetega midagi, nii ei ole seda ümberlülitust lihtsalt vaja)
Lihtsamal juhul piisab FOR tsükli sees alustada disableDelayedExpansion-ga, seejärel teha programmi loogika seisukohalt
täiesti jabur SETLOCAL käsk  koos tõesti vajaliku enableDelayedExpansion-ga
et siis ridu analüüsida-väljastada. 
Tsükli alguse muutujatesse aga peaks ka natukenegi keerukamatel juhtumitel 
midagi tagasi kirjutama ja siin 
algab uus nõiaring, sest alamprogrammidesse muutujate väärtusi edastada või sealt tagasi tuua ilma kadudeta ei ole lihtne, kui alati üldse võimalik. 
Selgub ka, kuivõrd napakas idee on SETLOCAL ja ENABLE/DISABLE DelayedExpansion ühte ritta kokku panna,
sest nad segavad üksteist sedavõrd, et sisuliselt muudavad normaalse programmi koostamise võimatuks.

Selle jutu tekkimise taustaks olid mõned skriptid, mida tahtsin millegipärast (pigem lõbu pärast) DOS-s kirjutada.
Need ei tahtnud ega tahtnud edeneda nendesamade märkide kadude tõttu.

Kokkuvõte:
Kui midagi prääksub nagu part ja näeb välja nagu part, siis ta ongi part.

Kui seal juba on mingi viga, siis ta ongi paha siga.

DOS ei ole siin mind alt vedanud.