Kde je môj diff
?
Pri skriptovaní v shelli sa neraz stáva, že chceme porovnať obsah dvoch súborov. Ak pracujete s nejakým systémom pre udržiavanie verzií (SVN a pod.) a chcete porovnať lokálnu kópiu s kópiu na serveri, viete, že použijete starý známy diff
.
Žiaľ, diff
nemusí byť nainštalovaný na každom systéme, a môžete sa diviť, či ešte má zmysel uvažovať o alternatívach. Určite má, pretože napr. na BusyBoxe (minimalistickom shelli použiteľnom napr. na Androide) diff
nie je.
Nepodliehajte však panike.
Máme tu comm
.
comm
Nápad porovnávať porovnávacie nástroje je celkom veselý, ale venovať sa mu nebudeme. V skratke: comm
je chudobný príbuzný diff
u, ale
- je súčasťou POSIXového štandardu pre unixovské systémy (na rozdiel od
diff
u) - pre mnohé jednoduché úlohy stačí.
Ukážme si fungovanie tohto nástroja na príklade s…
Tiobe
Tiobe.com je zábavný index udávajúci popularitu programovacích jazykov vo svete. Áno, prvá je Java, druhé je C. Skôr než sa rozčúlite nad oboma jazykmi, treba povedať, že tento index neudáva kvalitu jednotlivých jazykov (tu by Java nevyhrala) a dokonca ani poradie jazykov podľa množstva kódu, ktorý je v nich napísaný (tu by vyhral zrejme COBOL). Do úvahy sa berie množstvo dokumentov indexovaných webovými vyhľadávačmi (Google, Bing, Yahoo, Wikipedia a pod.). Hlavným účelom indexu je sledovať trendy (vedeli ste, že Objective-C letí nahor?) a napr. zistiť, či sa na tom-ktorom jazyku oplatí vo všeobecnosti postaviť nový systém.
Na webe indexu nájdete len dáta z posledného prepočtu, ale ak chcete obetovať 5000 dolárov, môžete získať kompletnú historickú sadu dát od roku 2001. Alebo pogooglite a nájdete niektoré archívne záznamy rozhádzané po blogoch a článkoch. Zoberme si napríklad stav z roku 2007 a porovnajme ho so súčasnosťou.
Pre jednoduchosť zoberme len prvých 10 jazykov, budeme ich musieť ručne prepísať do texťáku. Vyrobme si dva súbory: 2007.txt
a 2012.txt
.
Rok 2007:
1 java
2 c
3 basic
4 cpp
5 php
6 perl
7 python
8 csharp
9 ruby
10 javascript
Rok 2012:
1 java
2 c
3 csharp
4 cpp
5 objectivec
6 php
7 basic
8 python
9 perl
10 javascript
Ako zistiť, ktoré jazyky pribudli?
Ak chceme zistiť, ktoré jazyky pribudli a ktoré zmizli z prvej desiatky, vieme použiť horeuvedený comm
Skúsme prvý pokus. Vezmime oba súbory a rovno ich porovnajme.
novotnyr@x64:~/$ comm 2007.txt 2012.txt
1 java
2 c
3 basic
3 csharp
4 cpp
5 objectivec
5 php
6 perl
6 php
7 basic
7 python
8 csharp
8 python
9 perl
comm: file 2 is not in sorted order
10 javascript
9 ruby
comm: file 1 is not in sorted order
10 javascript
Uvidíme zmäť riadkov preloženú varovaniami File is not in sorted order
. Beda, čo sa stalo?
Zabudli sme prečítať man
.
Príkaz comm
vie porovnať obsahy dvoch súborov, ale predpokladá, že oba súbory mať zotriedené riadky. Napriek tomu, že z ľudského hľadiska sú riadky zotriedené, nie je to tak — triedenie v comm
totiž funguje na reťazcoch a predpokladá, že riadok 10 javascript
je pred 1 java
a nie na konci.
Zotriediť súbory však nie je problém: máme sort
! Ale počkajme ešte chvíľu.
Zrušenie poradových čísiel
Je tu ešte jeden problém: poradia jazykov. Každý riadok obsahuje číselné poradie, ale to nás v tejto chvíli až tak nezaujíma. Nie je dôležité, či bolo Ruby deviate alebo siedme, dôležité je, že v roku 2012 vypadlo z prvej desiatky.
Odstrániť čísla môžeme napr. cut
om. Keďže riadok pozostáva z dvoch „stĺpcov“ oddelených medzerou (v prvom je poradové číslo, v druhom meno jazyka), stačí z neho vyseknúť len druhý stĺpec.
cut 2007.txt -f2 -d' '
Parameter -f
indikuje, že nás zaujíma len druhý stĺpec. Parameter -d
zase nastaví medzeru ako oddeľovač stĺpcov, pretože v štandardnom móde cut
predpokladá, že oddeľovačom je tabulátor. (Medzeru uvedieme do apostrofov, indikujeme tým, že oddeľovačom je reťazec s jediným znakom medzery).
Sekanie a triedenie
Výstup z cut
môžete utriediť, aby sme nerozosmutnili comm
a výsledok uložme do bočného súboru.
cut 2007.txt -f2 -d' ' | sort > 2007s.txt
cut 2012.txt -f2 -d' ' | sort > 2012s.txt
Výstup je o niečo prijateľnejší, i keď stále chaotický:
basic
c
cpp
csharp
java
javascript
objectivec
perl
php
python
ruby
Co śie stao?
Výstupom comm
sú dáta o riadkových rozdieloch zobrazené v troch stĺpcoch oddelených tabulátormi. Prvý stĺpec obsahuje riadky, ktoré sú prítomné v prvom súbore, ale nie sú v druhom súbore (inak povedané, riadky, ktoré sa zmazali z prvého súboru). Druhý stĺpec obsahuje riadky prítomné v druhom súbore, ale chýbajúce v súbore č. 1. (riadky, ktoré pribudli). A iste si už domyslíte, že tretí stĺpec obsahuje riadky spoločné pre oba súbory.
Ak chcete vidieť len rozdielne riadky, použite parameter -3
, ktorým potlačíte tretí stĺpec.
novotnyr@x64:~/$ comm -3 2007s.txt 2012s.txt
objectivec
ruby
A ak chcete primeranejší tvar používajúci pluská a mínuská, môžete použiť sed
s dvoma príkazmi. V prvom kroku pred každý riadok dodáme [-]
a v ďalšom kroku každý riadok s kombináciou [-]\t
nahradíme kombináciou [+]
.
comm -3 2007s.txt 2012s.txt | sed -e 's/^/[-]/' -e 's/\[-\]\t/[+]/'
Výsledok?
Za päť rokov pribudlo v prvej desiatke Objective-C a ubudlo Ruby.
[+]objectivec
[-]ruby