wtorek, 11 sierpnia 2009

#2 Note: FOR /F "tokens=x delims=y"

Witam,
Dziś przedstawię możliwości pętli FOR, a konkretnie użycie pętli FOR ze słowami kluczowymi tokens= i delims=. Opierając się o definicję z help'a, słowo kluczowe tokens służy do określania tokenów, które mają być przekazane z każdego wiersza do głównego polecenia w każdej iteracji pętli FOR. Słowo kluczowe declims służy do określania zestawu ograniczników (może także zawierać spacje albo tabulator). Jednak definicje te nie są na tyle zrozumiałe by móc od razu swobodnie korzystać z tych funkcji. Dlatego zaczniemy od przykładu.

Na początku tworzymy sobie plik txt. Dla uproszczenia, mój plik nazwałem file.txt. W związku z tym, iż blog dotyczy języków skryptowych, a te często służą do pracy na plikach tekstowych, struktura mojego pliku przypomina plik csv.
Zawartość file.txt jest następująca:

1,jan,kowalski,82112102535,ul.Prosta 10/14,Warszawa
2,kamil,nowak,84051043987,ul.Krzywa 1/2,Krakow
3,barbara,nowacka,79010240598,ul.Cicha 15/124,Torun
4,piotr,kowalewski,65090844385,ul.Dluga 14a/12,Gdansk

I teraz chcemy pobrać z tego pliku jedynie informacje o nazwisku, peselu i mieście zamieszkania danej osoby. Załóżmy, że chcemy otrzymać plik tekstowy z zawartością:

kowalski;82112102535;Warszawa
nowak;84051043987;Krakow
nowacka;79010240598;Torun
kowalewski;65090844385;Gdansk

Jak to zrobić najłatwiej? Za pomocą wspomnianych słów kluczowych.

Tworzymy sobie batcha, który będzie zawierać jedynie jedną linię kodu:

@ECHO OFF

(FOR /F "tokens=3,4,6 delims=," %%a IN ([sciezka_do_naszego_pliku]\file.txt) do ECHO %%a;%%b;%%c) > Result.txt

Przejdźmy teraz do opisu działania naszej pętli FOR.
Przełącznik /F w pętli FOR służy do przekazywania pierwszego, oddzielonego spacją leksemu z każdego wiersza w pliku. Dzięki słowom kluczowym można zmienić sposób podziału wierszy w taki sposób jak chcemy. Słowo "tokens=3,4,6" służy do pobierania tokenów 3,4 i 6. Liczenie rozpoczynamy od 1, czyli token trzeci w naszym pliku tekstowym to nazwisko, token 4 to pesel, a token 6 to miasto. Za pomocą słowa "delims=," określamy jaki jest ogranicznik pomiędzy tokenami. W naszym wypadku jest to przecinek. Reasumując, "tokens=3,4,6 delims=," pobierze 'nazwisko,pesel,miasto'.

/*** PRZYDATNE ***
Gdybyśmy chcieli jeszcze imię, nie trzeba wymieniać wszystkich tokenów po przecinku - można podać zakres. Czyli na podstawie powyższego przykładu byłoby to "tokens=2-4,6 delims=," co oznacza "tokeny od 2 do 4 i jeszcze 6, oddzielone od siebie przecinkami".
*** PRZYDATNE ***/

Pod zmienna %%a kryje się zmienna systemowa. Możemy tam wpisać dowolną literkę, jednak należy o tych pamiętać przy wyświetlaniu wyniku. Instrukcja "ECHO %%a;%%b;%%c" wyświetli nam informację dla każdego z wymienionych tokenów, oddzielając je średnikami. Czyli w naszym przykładzie tokens=3 to %%a, tokens=4 to %%b i tokens=6 to %%c. Gdybyśmy mieli więcej tokenów musimy podać kolejne zmienne systemowe (jednoliterowe z zakresu a-z). Następnie umieszczamy całe wyrażenie FOR w nawiasach i przekierowujemy strumień na plik Result.txt do którego zostanie zapisany wynik działania pętli FOR.

A co w przypadku, gdy mamy błędne wiersze w naszym pliku i na przykład rozpoczynają się od znaku kropki? Wystarczy dodać do opcji pętli FOR słowo kluczowe eol= określające linie, które mają zostać pomienięte. Np.:

File.txt
1,jan,kowalski,82112102535,ul.Prosta 10/14,Warszawa
2,kamil,nowak,84051043987,ul.Krzywa 1/2,Krakow
3,barbara,nowacka,79010240598,ul.Cicha 15/124,Torun
4,piotr,kowalewski,65090844385,ul.Dluga 14a/12,Gdansk
.5,tomek,kowal,89040621857,ul.Jasna 29/1,Wroclaw

Plik *.bat
@ECHO OFF

(FOR /F "eol=. tokens=3,4,6 delims=," %%a IN ([sciezka_do_naszego_pliku]\file.txt) do ECHO %%a;%%b;%%c) > Result.txt

Result.txt
kowalski;82112102535;Warszawa
nowak;84051043987;Krakow
nowacka;79010240598;Torun
kowalewski;65090844385;Gdansk

Ostatnia linia zostanie pominięta, ponieważ rozpoczyna się od kropki. Ważne jest, że do słowa kluczowego eol= możemy przypisać jedynie jeden znak, zarówno alfanumeryczny jak i znak specjalny.


Do pętli FOR jeszcze na pewno wrócę, ponieważ oferuje ona bardzo szeroki zakres możliwości. Jednak aby posty były zrozumiałe i zwięzłe, ograniczę się jedynie do zapoznania i przedstawienia kolejnych elementów zawartych w plikach wsadowych Windows.

-------------------------------------------------------------------------------------

Hello,
Today I present you a FOR loop possibilities, especially use FOR loop with key words tokens= and delims=. Base on the definition from dos help, key word tokens specifies tokens which should be passed from each line to the FOR body for each iteration. Key word declims specifies a delimiter set (may contain a spacebar or tab). But these definitions aren't sufficiently well understood to be able to freely use. Therefore we start with example.

At the beginning we create a text file. For simplification I named my file file.txt. Therefore that this blog is about scripting languages and these are often useful to work with text files, structure of my file is like csv file.
Content of file.txt is following:

1,jan,kowalski,82112102535,ul.Prosta 10/14,Warszawa
2,kamil,nowak,84051043987,ul.Krzywa 1/2,Krakow
3,barbara,nowacka,79010240598,ul.Cicha 15/124,Torun
4,piotr,kowalewski,65090844385,ul.Dluga 14a/12,Gdansk

And now we want to get from this file information about surname, pesel and city. For example we want to obtain a text file containes:

kowalski;82112102535;Warszawa
nowak;84051043987;Krakow
nowacka;79010240598;Torun
kowalewski;65090844385;Gdansk

How to do this the easiest way? By mentioned key words.
We create a batch file, which will contain only one line of code:

@ECHO OFF

(FOR /F "tokens=3,4,6 delims=," %%a IN ([path_to_our_file]\file.txt) do ECHO %%a;%%b;%%c) > Result.txt

No we go to describe how our FOR loop works.
Switch /F is used to pass first space-separated lexem from each row in a file. By key words we can change apportionment of lines in such way what we want. Word “tokens=3,4,6” attend to take tokens 3,4 and 6. We start counting from 1, that mean the third token in our file is surname, fourth token is pesel no. and sixth token is a city. By word “delims=,” we attend the delimiter between our tokens. In our case there is a comma. In summary, “tokens=3,4,6 delims=,” took ‘surname,pesel,city’.

/*** USEFUL ***
When we want to add a name to our result, we shouldn’t took all of tokens after comma – we can give a range. Based on example above it would be “tokens=2-4,6 delims=,” what mean “take tokens from second to fourth and also six, all separated with comma”.
*** USEFUL ***/

Variable %%a is a system variable. We can enter there any letter, but we must remember about it when we want to print result. Instruction “ECHO %%a;%%b;%%c” prints us an information for each for mentioned tokens, separated by semicolons. In our example tokens=3 is a variable %%a, tokens=4 is a variable %%b and tokens=6 is a variable %%c. If we had more tokens we must give next system variables (one letter from a-z range). Next we put whole FOR expression in parentheses and redirect stream to file Result.txt which saved result of FOR loop work.

And what in case when we have an incorrect rows in our file and some of them begin with a dot? We only need to add to FOR loop options a key word eol= which specifies rows which should be omitted. For example:

File.txt
1,jan,kowalski,82112102535,ul.Prosta 10/14,Warszawa
2,kamil,nowak,84051043987,ul.Krzywa 1/2,Krakow
3,barbara,nowacka,79010240598,ul.Cicha 15/124,Torun
4,piotr,kowalewski,65090844385,ul.Dluga 14a/12,Gdansk
.5,tomek,kowal,89040621857,ul.Jasna 29/1,Wroclaw

File *.bat
@ECHO OFF

(FOR /F "eol=. tokens=3,4,6 delims=," %%a IN ([path_to_our_file]\file.txt) do ECHO %%a;%%b;%%c) > Result.txt

Result.txt
kowalski;82112102535;Warszawa
nowak;84051043987;Krakow
nowacka;79010240598;Torun
kowalewski;65090844385;Gdansk

Last row will be skipped because it starts with a dot. It is important that we can assign only one character to key word eol= both alphanumerical and a special character.

I will come back to FOR loop because it offers a very wide range of possibilities. However, to the post are understandable and concise, I confined myself to introduce consecutive elements in Windows batch files.

piątek, 7 sierpnia 2009

#1 Note: SET var=%DATE:~a,b%

Ten post pokaże po krótce to, że znane wszystkim pliki bat wcale nie muszą być prostymi skryptami uruchamiającymi inne programy. Na poczatek może zaczniemy od jakiegoś przykładu:

@ECHO OFF
%DATE%

PAUSE>NUL

Jest to prosty skrypt wyświetlający aktualną datę. Problem polega na tym, że rodzaj zapisu daty jest zależny od ustawień na danej stacji. Spróbujcie uruchomić to samo na innych komputerach i zobaczcie czy za każdym razem otrzymacie identyczny format daty ;)
To nasuwa nam problem, w przypadku gdy chcemy aby data była zawsze prezentowana w taki sam sposób, niezależnie od ustawień w systemie. Co w przypadku gdy chcemy wypisać na ekran datę w postaci 06.08.2009? Albo 2009/08/06? Niestety nie jesteśmy w stanie zmieniać ustawień każdego komputera na którym miałby być uruchamiany ten - na pozór prosty - skrypt. Z pomocą przychodzi nam polecenie

SET var=%DATE:~a,b%

Zastosowanie powyższego polecenia pozwala nam wyciągać poszczególne substringi, a następnie ustawiać w takiej kolejności w jakiej sobie tylko zażyczymy.
Mały przykład:

@ECHO OFF
ECHO Data na moim komputerze ma postac: %DATE%
IF /i "%DATE:~-3,-2%"=="-" SET CURR=%DATE:~-2%.%DATE:~-5,-3%.%DATE:~-10,-6%
IF /i "%DATE:~-5,-4%"=="-" SET CURR=%DATE:~-10,-8%.%DATE:~-7,-5%.%DATA:~-4%
IF /i "%DATE:~-5,-4%"=="/" SET CURR=%DATE:~-10,-8%.%DATE:~-7,-5%.%DATA:~-4%
ECHO Po przeformatowaniu, data ma postac: %CURR%

PAUSE>NUL

Uruchomcie powyższy skrypt. Prawda, że proste? :) Teraz wytłumaczę co się dzieję w powyższym kodzie.

Wykonanie instrukcji "ECHO Data na moim komputerze ma postac: %DATE%" powoduje wyświetlenie na konsoli bieżącego formatu daty jaki mamy ustawiony w systemie.
W zwiazku z tym, że data w Windowsach może mieć następujący format:
06/08/2009
06-08-2009
2009-08-06
musimy mieć trzy IF'y, które biorą pod uwagę każdą z tych możliwości. Przełącznik /i w funkcji IF służy do porównania dwóch stringów (dzięki niemu możemy korzystać z zapisu string1==string2). Następnie przechodzimy do polecenia o którym wspominałem na początku tego posta. Otóż, jest to o wiele łatwiejsze niż by się mogło wydawać. Zapis

"%DATE:~-3,-2%"=="-"

oznacza nic innego jak "dla wyniku wywołania zmiennej DATE w systemie, zapamiętaj substring od 3 znaku od końca do 2 znaku od końca, a następnie porównaj ze znakiem myślnika "-". Po dwukropku musimy pamiętać o znaku tyldy (~). Pod zmienne a i b podstawiamy numer znaku, na zasadzie 'od a do b'. W naszym przykładzie jest jeszcze znak minusa, oznaczający liczenie znaków od końca stringa. Czyli jak łatwo się zorientować, zapis "%DATE:~-3,-2%"=="-" dotyczy formatowania daty w postaci 2009-08-06 (- jest 3 znakiem od końca). Dalej tworzymy sobie zmienna CURR, w której formatujemy datę dla tego konkretnego przypadku.

SET CURR=%DATE:~-2%.%DATE:~-5,-3%.%DATE:~-10,-6%

Można opisać następująco: ustaw zmienna CURR, która będzie równa: od drugiego znaku od końca do zerowego od końca, z systemowego formatowania daty (czyli 06) -> kropka -> od piątego od końca do trzeciego znaku od końca (czyli 08) -> kropka -> od 10 od końca do 6 od końca (2009). Taki zapis przypisuje zmiennej CURR datę w postaci 06.08.2009.
Dla pozostałych IF'ów sytuacja jest analogiczna, więc nie będę ich już rozpisywał :)

Następnie wyświetlamy zawartość zmiennej CURR, która będzie zawierała datę w postaci DD.MM.RRRR, niezależnie od domyślnego formatowania daty w systemie.



Prawda, że proste? ;)


PS. Powyższy przykład dotyczy formatowania daty, jednak nie oznacza to, że tylko w tym wypadku mamy możliwość formatowania stringa. To samo możemy zrobić na przykład ze zmienna systemową TIME, czy z własnymi zmiennymi, które potrzebujemy odpowiednio przeformatować.

-------------------------------------------------------------------------------------

This post will show that known to all bat files, not at all be easy scripts which starts other applications. Maybe at the beginning we begin with an example:

@ECHO OFF
%DATE%

PAUSE>NUL

This is simple script that displays current date. The problem is that the type of date notation is determined at a given PC settings. Try to run this script on different PCs and look whether date format will be the same each time ;) This raises to mind that in case when we want to show date always in the same way, regardless of system settings. What in case when we want to print date in form 06.08.2009 on screen? Or 2009/08/06? Unfortunately, we are not able to change the setting of each computer where this (seemingly simple) script would be run. With the assistance comes to us following command

SET var=%DATE:~a,b%

Applaying command above, allows us to draw specific substrings and then set in order which we would like. Small example:

@ECHO OFF
ECHO Date on my computer is: %DATE%
IF /i "%DATE:~-3,-2%"=="-" SET CURR=%DATE:~-2%.%DATE:~-5,-3%.%DATE:~-10,-6%
IF /i "%DATE:~-5,-4%"=="-" SET CURR=%DATE:~-10,-8%.%DATE:~-7,-5%.%DATA:~-4%
IF /i "%DATE:~-5,-4%"=="/" SET CURR=%DATE:~-10,-8%.%DATE:~-7,-5%.%DATA:~-4%
ECHO After formatting, date on my computer is: %CURR%

PAUSE>NUL

Please run above script. Simple, true? :) Now I explain what is really going on this code.

Instruction „ECHO Date on my computer is: %DATE%” causes print on console currently date format which we have set in the system. Therefore that data in Windows can have following format:
06/08/2009
06-08-2009
2009-08-06
we must have three IF conditions which take each of these possibilities. Switch /i in function IF occurs to compare two strings (with this tool we can use notation string1==string2). Next we go to command about I mentioned at the beginning of this post. This is more easier than that would seem. Notation

"%DATE:~-3,-2%"=="-"

means nothing else like „for result of call DATE system variable, remember substring from the third sign of the end to the second sign of the end, next compare it with dash sign „-”. After colon we must remember about tilde sign (~). Under variables a and b we put sign number on a rule „from a to b”. In our example exist also a minus sign, which means counting characters from the end of string. That is how easy to find, notice "%DATE:~-3,-2%"=="-" is related with 2009-08-06 date format (minus is the third sign of the end). Further we create variable CURR , where we formatting date for that case.

SET CURR=%DATE:~-2%.%DATE:~-5,-3%.%DATE:~-10,-6%

Can be described as follows: set the variable CURR which will be equal to: from the second sign of the end to the zero sign of the end from system formated date (06) → dot → from the fifth sign of the end to the third sign of the end (08) → dot → from tenth sign of the end to sixth sign of the end (2009). This notation assigned to variable CURR date as 06.08.2009. For rest of IF conditions situation is analogous, so I'll not describe them :)

Next we print content of variable CURR, which will contained date as DD.MM.YYYY, regardless of default date format in system.



This is simple, true? :)


PS. Example above is related to date format, but this doesn't mean that we can use this possibility only in that case. The same we can do for example with system variable TIME, or with own variables which we want to format properly.

czwartek, 6 sierpnia 2009

Wstęp/Introduction

Cześć!
Mam na imię Michał i jestem studentem Polsko-Japońskiej Wyższej Szkoły Technik Komputerowych w Warszawie. W związku z tym, iż zacząłem interesować się językami skryptowymi, postanowiłem utworzyć bloga, na łamach którego będę publikował różne ciekawe i mniej lub bardziej przydatne informacje :) To na czym się skupię (przynajmniej na początku), to Windowsowe skrypty batch oraz Linuxowe skrypty w bashu. W miarę możliwości i poziomu zdobywanej przeze mnie wiedzy, postaram się także wspominać o Perlu, Pythonie (zarówno w Windows jak i w Linuxie) oraz JavaScript. Mam nadzieję, że informację jakie będę tu umieszczał zainteresują Was i pomogą w zrozumieniu wymienionych wyżej języków.

Ruszajmy!

-------------------------------------------------------------------------------------

Hi,
My name is Michal and I'm a student of Polish Japanese Institute of Information Technology in Warsaw. Therefore that I began an interest in scripting languages, I decided to create a blog where I'll publish some interesting and more or less useful information :) I'll concetrate (at least at the beginning) on Windows batch scripts and Linux bash scripts. As far as possible and the level of knowledge acquired by me, I'll try to mention about Perl, Python (both on Windows and Linux) and also about JavaScript. I hope that the information that I'll place here will be interesting for you and will help in understanding languages mentioned above.

Let's start!