HTML

Bagoj úr blogja

Kíváncsi Bagoj befigyel a Linux belsejébe, illetve különféle Linux terjesztéseket próbál ki. Ha jó napja van, scriptet ír Neked.

Friss topikok

Újabb sed agyszülemények

2012.07.01. 00:28 bagoj ur

Egy konkrét kérés nyomán volt szükségem néhány gyors szöveg manipulálásra, amelyhez a sed (stream editor) segítségét választottam. A kérés egy utónév kereső és kalkulátor lefejesztése volt, amelyhez szükségem volt természetesen az adatbázisra. Az összes, Magyar Tudományos Akadémia által jóváhagyott nevet nyilvánosan, PDF formátumban le lehet tölteni a honlapjukról (khm.... mint az közismert).

A Zathura nevű PDF olvasó játszva kimásolta a neveket egy szöveges fájlba; mindössze annyi volt zavaró, hogy belemásolta az oldalszámot és a kezdőbetűt jelölő fejezetcímeket (A, B, C stb) is. Mivel kétbetűs névről nem tudok (a Leó, Lea, Mia és ezek a legrövidebbek), ezért azokat a sorokat töröltem a fájlból, amelyek összesen 1 vagy 2 karakterből állnak (így a kettősbetű jelölőket is kizártam *):

cat tmp.txt | sed '/^.$/d' | sed '/^..$/d' > lanynevek.txt

Szükségem volt még a gyakran kiosztott nevekre - a szoftver bármilyen okos egyezést meg tud találni, kivéve azt, hogy a szülőknek az utóbbi időben most éppen mely nevek tetszettek. A www.nevnaptar.eu oldalon fent vannak a népszerű nevek. Gyorsan kijelöltem, ctrl+Cecil, ctrl+Vazul, de sajnos a szövegfájlba már így kerültek be a nevek (mindenféle egyéb szemét is jött velük, ráadásul csupa nagybetűsek voltak):

1.
JÁZMIN
    1 559     334
2.
ANNA
    1 255     659
3.
HANNA
    1 207     251

A legpraktikusabbnak azt tartottam, ha a számozott sorokat kihagyom, ezért csak azokat a sorokat írattam ki, amelyekben betűk szerepelnek (ugye nevek esetén viszonylag ritkán bukkannak fel számok, hacsak nem valakit T1b0r-nak hívnak :-)). Persze szórakozhattam volna mindenféle 'n;d;n;n;d;n;d' parancsokkal is... :)

sed -n '/^[A-Z]*$/p' gyakorinevek.txt > gyn_temp.txt

A nagybetűs nevek ettől még megmaradtak. Kapitalizáltam őket úgy, hogy az első betűre match-eltem és azt változatlanul kiírattam, a többit pedig a \L direktívával kisbetűssé alakítottam.

sed 's/^\([A-Z]\)\([A-Z]*\)$/\1\L\2/' gyn_temp.txt > gyakorinevek.txt

Itt ugye a visszahivatkozásokat hívtam segítségül.

Ha összegezzük a fentieket, lényegében 3 sorból előállt két adatbázis, amiben később tudtam keresgélni. Természetesen ezeket a sort paranccsal még rendeztem a felhasználás előtt.

Zisz iz de póver ov kommandlájn interfész.

*Benne maradt a Dzs, mint utólag kiderült... :)

3 komment

Címkék: szkript parancssor sed

Képernyő mentés - mini szkript

2012.06.10. 21:47 bagoj ur

Az alábbi kis egysoros nem is nevezhető szkriptnek. Azért készítettem, mert (mint az közismert) Gnome 3-at használok és Arch Linux alatt nem telepítődik fel függőségként például a gnome-screenshot nevű alkalmazás. Azt gondoltam, nekem erre nincs is szükségem, viszont az jó, ha a print screen megnyomására történik valami. Nem kívántam átírni az alapértelmezett forróbillentyű beállításokat, így a szkriptet /usr/bin/gnome-screenshot néven mentettem el:

#!/bin/bash
import -window root ~/screenshot_$(/bin/date +%Y%m%d%H%I%S).jpg
Nem túl sok, igaz? Magyarázat:

A date parancs kimenete paraméterezhető, megadható hogy a dátumot és időt milyen formátumban írja ki. Itt éppen ÉÉÉÉHHNNÓÓPPMM formátumban íratom ki, további lehetőségekért ajánlom a man date olvasgatását, határozottan idegnyugtató.

Az import nevű parancs pedig az Imagemagick csomag része, amely nekem speciel az Inkscape miatt települt fel és jó, hogy van.

A fenti egysoros tehát a home könyvtáromba rakja el a képet, screenshot_<aktuális dátum és idő>.jpg néven (és formátumban). Egyszerű, de hasznos.

Szólj hozzá!

Címkék: linux egyszerű szkript terminal képernyőmentés

Színezzük át a Gnome témát a háttérképnek megfelelően

2012.05.29. 23:59 bagoj ur

Olvasom az okosságot nemrégiben: egy valószínűleg rettenetesen unatkozó programozó kitalálta, hogy nem csak a háttérképet cserélgeti a Gnome3 alatt, hanem egy (Python) szkripttel megnézi, hogy mi a beállított háttérkép átlagos színárnyalata, és beállítja ahhoz a GTK téma megfelelő színeit. Kicsit viccesnek találtam a dolgot, de miért ne foglalkozzak vele?

Röviden elemezve a szkriptjét, kiderül hogy a tuti parancs a következő: 

/usr/bin/xprop -root _GNOME_BACKGROUND_REPRESENTATIVE_COLORS

 

Ez elég megdöbbentő módon tényleg kiírja RGB kóddal a háttérkép átlagos színárnyalatát! Hogy mik vannak így 2012-ben...

_GNOME_BACKGROUND_REPRESENTATIVE_COLORS(STRING) = "rgb(45,61,113)"

Ha már ez ilyen egyszerű, akkor ezt a Bash is tudja... :-) Egy titka van a dolognak; ahhoz hogy felhasználó-szinten tudjuk állítgatni egy téma színárnyalatait, nyilvánvalóan egy felhasználói témát kell tudnunk alkalmazni.

A Gnome3 rendszertémák a /usr/share/themes alatt találhatók; az alapértelmezett az Adwaita névre hallgat (nekem nagyon tetszik is, ügyesek voltak a grafikusok). A téma könyvtárában pedig van egy gtk-3.0 könyvtár, abban pedig egy gtk.css fájl, benne a színkódokkal. Ha az Adwaita könyvtárat bemásoljuk a home könyvtárunkban a .themes könyvtár alá (ha nincs, létre kell hozni), akkor elő is állt a felhasználói téma, amelyet már tudunk módosítani. Az ebben lévő színkódokat kell megmachinálnunk.

Ha már a Gnome 3.4-et vagy újabbat koptatunk, akkor ehelyütt van egy kis probléma: a felület gyorsítása érdekében a 3.2-ig text formátumú fájl helyett a 3.4-től egy binárist alkalmaznak, és az említett gtk.css-ben mindössze ennyi van:

@import url("resource:///org/gnome/adwaita/gtk-main.css");

Ez igen sajnálatos a mi szempontunkból, mert a bináris fájlt egyelőre nem tudjuk írni. :-( Én letöltöttem tehát a Gnome 3.2-höz tartozó Adwaita témát, és Adwaita-bagoj néven bemásoltam a .themes alá.

Miután a fenti nehézségen túljutottunk, íme az én kis túlbonyolított szkriptem egyetlen érték átírására (ez a "fénygerenda" színe, és a szkript futtatása után minden újonnan elindított alkalmazásnál látszik is a változás, hogy a kijelölt menüpontok ilyen színűek lesznek).

#!/bin/bash

THEME_NAME="Adwaita-bagoj"
USER=`/usr/bin/whoami`

R=; G=; B=; I=0;

while IFS= read -r -d , a; do
    if [ "1"$I = "12" ]; then
        B=$a;
        let I $((I++));
    fi
    if [ "1"$I = "11" ]; then
        G=$a;
        let I $((I++));
    fi
    if [ "1"$I = "10" ]; then
        R=$a;
        let I $((I++));
    fi
done < <(/usr/bin/xprop -root _GNOME_BACKGROUND_REPRESENTATIVE_COLORS | sed s_^.*rgb\(__ | sed s_\).*_,_);

sed "s/@define-color\ selected_bg_color\ \(.*\)/@define-color selected_bg_color rgb ($R, $G, $B);/" /home/$USER/.themes/$THEME_NAME/gtk-3.0/gtk.css > /home/$USER/.themes/$THEME_NAME/gtk-3.0/gtk.css_new
mv /home/$USER/.themes/$THEME_NAME/gtk-3.0/gtk.css_new /home/$USER/.themes/$THEME_NAME/gtk-3.0/gtk.css
Aki nem szeretné egyből felülírni a gtk.css fájlt, az utolsó sort kommentezze ki, ekkor csak egy gtk.css_new áll elő, amit meg lehet nézni text editorban, hogy minden oké-e.

Nem tudom, van szükség magyarázatra? Én szívesen elregélem, csak dobjatok egy kommentet. :-)

Még annyi fényezni való lenne, hogy a GTK2-es alkalmazások számára a téma gtk-2.0 könyvtárában (egy másik szintaxissal) is be kéne írni azt a bizonyos színt. Ma késő van, fáradt Bagoj vagyok, de be fogom pótolni, ok?

2 komment

Címkék: linux gnome script parancssor arch gnome3

Arch Linux + wifi

2012.05.28. 22:36 bagoj ur

Valószínűleg többen simán le fognak hülyézni, hogy a nagyon kényelmes, jól kezelhető és grafikus Network Manager helyett én már megint szkripteztem. Ennek az az oka, hogy sok időt töltöttem el fekete hátterű konzolok előtt, és még mindig jobban kézreáll a parancssor, ráadásul élvezettel tölt el egy-egy újabb szkriptecske létrehozása.

Nem mértem, hogy a gép fogyasztása vagy a boot idő kevesebb lett volna-e a saját szkripttel, ez nem is érdekelt különösebben, de nem hiszem hogy mérhető különbség lenne. Fogjuk fel különcségnek az alábbiakat.

A lényeg tehát, hogy WPA2 titkosítás van itthon, a wpa_supplicant nevű csomagot kell beizzítani hozzá, és be kell konfigurálni a /etc/wpa_supplicant.conf-ban:

ctrl_interface=/var/run/wpa_supplicant
eapol_version=1
ap_scan=1
fast_reauth=1
bss_max_count=100

network={
    ssid="Linksys"
    psk="titkos"
    priority=2
}

network={
        ssid="D-Link"
        psk="titkos2"
        priority=2
}
Mint látható, ahány hálózat van, mindegyiknél meg kell adni az SSID-t (a hálózat nevét), és a jelszót. A prioritás sorrendjében halad, illetve ha nem tud felcsatlakozni az elsőhöz, megy a következőre stb.

Jogos észrevétel, hogy ha olyan wifi hálózatra kell csatlakoznom, amelyet nem ismerek előre, akkor nem tudom előre meghatározni a fenti fájl tartalmát. Aki sokat rohangál és mindenfelé felcsatlakozik, az tegye fel a Network Managert.

Az alábbi szkript izzítja a hálózatot, /etc/rc.d/wifi néven fut, és persze a /etc/rc.conf-ba be kell írni a futtatandó szolgáltatások közé azt is, hogy @wifi.

#!/bin/bash

ip link set wlan0 up
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
E=0
until [ $E == 5 ]; do
    dhcpcd wlan0
    if [ $? != 0 ]; then
        let E $((E++))
        W=$((E*10))
        echo "Waiting for $W seconds..."
        sleep $W
    else
        exit 0
    fi
done
Állj, állj... mi ez az until...do rész már megint?

Nos, menjünk talán sorban:

  1. Az "ip link..." sor felhúzza up-ba logikailag a wlan0 interfészt, vagyis az én vezeték nélküli hálózati interfészemet
  2. A "wpa_supplicant..."-es sor meghívja a WPA segéderőt, "aki" elintézi az Access Pointhoz való csatlakozást, azonosítással egyetemben
  3. Itt egy kis ciklus következik, mert nekem nem túl gyors a DHCP, néha nem sikerült elsőre IP-t kapnom, ami bosszantó volt, hiszen a grafikus felület közben elindul és még csak nem is láttam, hogy probléma van, utána parancssor, bogarászás stb. Meguntam. Ez a kis ciklus kér egy IP-t, ha ez sikertelen, akkor egyre többet (10,20,30,40,50 másodpercet) vár, és újra próbálkozik.

Ha igazán paranoid lennék, az egészet betenném még egy ciklusba, és mondjuk 5 percenként néznék egy ping-et egy jól ismert címre, és ha az sikertelen, akkor ismét megpróbálom a csatlakozást. De ez egy laptop, nem fogom a drága akssiidőt ilyenekkel tölteni... ha nincs hálózat boot-kor, később majd futtatom a szkriptet kézzel. :)

Hát, ennyi. Nem nagy dolgok, de ezzel (is) töltöttem az Arch installt követő időszakot. Egy démonnal (a NetworkManager-rel) kevesebb fut nálam, ez is valami.

Szólj hozzá!

Címkék: linux wifi hogyan parancssor arch

Dayfolder, jó ötlet könyvtáraink tisztán tartására (+ ingyen szkript ;-)

2012.05.22. 23:12 bagoj ur

Most olvasom, hogy van egy Dayfolder nevű alkalmazásocska, amely arra szolgál, hogy a Desktopon felgyülemlett "szemetet", azaz leginkább fájlokat egy logikus elrendezés szerint könyvtárakba rakja.

Konkrétan, sok felhasználó van, aki a Desktopot használja mindenféle átmeneti vicikvacak fájlok tárolására, meg letöltésre, hiszen ezek onnan bármikor könnyen elérhetők. Viszont egy idő után természetesen nem csak ronda lesz a desktopunk, hanem már fájlkezelőben megnyitva is alig találunk meg dolgokat, annyi mindent pakolunk oda. A programocska nem csinál mást, mint becsücsül a tálcánkra, és futtatásakor egy előre megadott könyvtáron belül mindegyik fájlt a mentési (vagy legutóbbi elérési, ez nem derül ki) dátumának megfelelő alkönyvtárba pakol át (ha szükséges, létrehozva a könyvtárat). Ezzel a Desktopunk mintegy varázsütésre kiürül, cserébe valahol a gépen egy eldugott folderben óriásira nő a szeméthegy, de az minket már nem zavar. :-) Nem csak napi, de heti vagy havi könyvtár kezelésére is alkalmas a cucc.

Megadhatók további egyszerű szabályok is, amelyek a fenti igen egyszerű működést kiegészítik, pl. a kép fájlokat a Pictures mappába mozgassa inkább. Mivel akárhány ilyen szabályunk lehet, eléggé szépen be lehet lőni a működést.

Tök jó kis alkalmazás tehát ez. El is határoztam, hogy a Downloads mappám rendezésére fogok használni egy saját szkriptet hasonló céllal, és ez jó alkalom arra, hogy megint írjak valami nem túl bonyolultat de talán minimálisan hasznosat.

Mi a feladat?

  1. Találjuk meg a fájlokat az adott könyvtárban
  2. Nézzük meg, mi a fájl dátuma
  3. Ha még nem létezik az éé-hh-nn nevű dátum könyvtár, létrehozzuk
  4. A fájlt belemozgatjuk a dátum könyvtárba

A fájlok keresését a jó öreg find paranccsal fogjuk elvégezni, amelynek kimenetét feldolgozzuk.

find -maxdepth 1 -type f

Az ls parancs megfelelő kapcsolóval kiírja ISO formátumban a dátumot és időt; nekünk ebből csak a dátum kell, ezért az awk-kal kiszedjük csak azt a mezőt.

ls --full-time | awk '{print $6}'

Mivel eltérő bash és ls verziók, illetve egyéni beállítások befolyásolhatják, hogy a fenti sor tényleg a fájlok dátumát írja ki, ezért legegyszerűbb, ha leellenőrizzük.

Ezután csak arra van szükség, hogy megnézzük, létezik-e a könyvtár, és ha nem, akkor létrehozzuk, illetve az mv-vel bemozgatjuk a fájlt. Mivel ezt a részt önmagában nehéz kiszedni a mini-szkriptből, ezért most közreadom mindazt, amit eddig készítettem:

#!/bin/bash

while IFS= read -r -d $'\0' file; do
    D=$(ls --full-time "$file"|awk '{print $6}')
    if [ ! -d "$D" ]; then
        mkdir "$D"
    fi
    mv "$file" "$D"
done < <(find -maxdepth 1 -type f -print0)
Rögtön egy magyarázattal tartozom, mi ez a sok read, meg while??? Nem annyira veszélyes...

A probléma

Nos, van egy örök probléma a bash szkriptekkel, ez pedig ugyebár az, hogy ha egy fájlnévben szóköz van, akkor a szövegfeldolgozás gyorsan elhasalhat. Ha ilyen formában fogalmazom meg a fájlok felkeresését:

for i in $(find -maxdepth 1 -type f); do
        echo $i
done
akkor csúnya lyukra tudok futni, pl:

./Kerekes
Band
feat_
Mégötlövés
-
Mr_
Hungary
(OFFICIAL
VIDEO)-[www_flv2mp3_com].mp3
Mint az jól látszik, minden szóközből sortörés lett. Miért van ez így? Mint minden jó szoftverben, a bash-ben is be lehet állírani, hogy mit tekintsen szeparátornak, ezt az IFS (Internal Field Separator) nevű változóban tehetjük meg. Ami ide be van állítva, azok mentén tördeli a sztringeket. Le kell hát dumálnunk arról, hogy a szóközöknél ezt megtegye!

Emellett arra is szükségünk van azonban, hogy a find parancs se darabolja fel ilyen ronda módon a fájlneveket. Megmondjuk neki, hogy a fájlneveket a \0 karakterrel szeparálja, hasonlóan a C nyelvhez. Mivel ez alapból nem megjeleníthető karakter, kizárt hogy egy fájlnév ilyet tartalmazzon, tehát biztonsággal használhatjuk. Na igen, de a find által megtalált, \0-val szeparált bithalmazt valamivel fel kell tudnunk olvasni.

Erre van több lehetőség is, pl. az xargs is tudja a -0 paraméterrel, de én bevallom férfiasan, nem szeretem annyira az xargs-ot, és nekem kényelmesebb az én megoldásom:

  1. A find-ot tehát beállítjuk, hogy a 0 bájttal szeparáljon és adagolja az eredményt bele a "while read.... done" ciklusba. Ami tehát addig olvas, amíg csak van bemenet. Eddig jó. Az IFS= rész lenullázza a már fentebb említett beállítást, tehát ilyenkor nem szeparálja a fájlneveket a bash semmi mentén. Ez jó dolog, mert a kontroll innentől nálunk van.
  2. A read "-d" paraméterében beállítjuk, hogy az újsor karaktert, és a \0 karaktert kezeljük sortörésként. Innentől a bash nem mondja meg, de mi megmondjuk a read-nek, hogy mi alapján tördelje a fájlneveket
  3. A $file nevű változóban van mindig az aktuális fájlnév. Most már kiveséztük a read parancs minden paraméterét. Tehát a find pumpálja a ciklusba a fájl keresés eredményét, ezt a read parancs beolvassa mindig a $file változóba, az általunk megadott tördeléssel.

A következő lépésben a D (vagyis $D) változóba a fentebb kivesézett ls paranccsal beletöltöm az aktuális fájl dátumát. A szögletes zárójel (mint az közismert) a bash beépített test utasításának aliasa, tehát a könyvtár létezésére vonatkozó feltételt írhattam volna valahogy így is:

    if test ! -d "$D"; then
        mkdir "$D"
    fi

de sokkal kompaktabb a [ .... ] formátum, ezért mindenütt így írják.

A könyvtár létrejött, már csak egy mv szükségeltetik, hogy a fájl átkerüljön a napi könyvtárba.

Finomítás

Minden szép és jó, de mi van, ha nem akarjuk az összes fájlt mozgatni? Például bizonyos kiterjesztéseket szeretnénk ott hagyni, ahol van. Ez feltétlenül jogos igény... lássuk csak.

A bash 3-as verziójától van lehetőség a regexp match-re, vagyis a reguláris kifejezés illesztésre. Ez igen hasonló a perl nyelvben használthoz, csak itt dupla szögletes zárójelen belül lehet használni, valahogy így:

if [[ "Elmentem horgaszni" =~ horg.....$ ]]; then
        echo "Jó pecázást"
fi
A kulcs tehát a =~ nevű operátor. Nem most akarok kitérni a regexp alapjaira, de a fenti kis részletnek ki kellene írni, hogy "Jó pecázást".

A fenti operátort fogjuk használni a javított szkripthez. Az egész elején szóközzel elválasztva berakjuk egy változóba a kiterjesztéseket (pontosabban fájlnév végeket, hiszen a Linuxban sosem volt kiterjesztése a fájloknak olyan értelemben, ahogy a DOS világból örököltük), amiket akarunk. A kódba pedig bekerül egy rövid kis ciklus, ami ezeken a szóközzel elválasztott kiterjesztéseken megy keresztül, megnézi hogy az adott fájlnévre ráilleszkedik-e, és ha igen, akkor átállítja a MOVE nevű változó értékét üresre. Ennek következtében nem fogjuk mozgatni a fájlt:

#!/bin/bash

PROTECTED_FILES='mp3 avi'

while IFS= read -r -d $'\0' file; do
        MOVE=1
        for e in $PROTECTED_FILES; do
                if [[ "$file" =~ "$e"$ ]]; then
                        MOVE=
                fi
        done

        if [ 1"$MOVE" = "11" ]; then
                D=$(ls --full-time "$file"|awk '{print $6}')

                if [ ! -d "$D" ]; then
                        mkdir "$D"
                fi
                mv "$file" "$D"
        fi       
done < <(find -maxdepth 1 -type f -print0)
Kiemeltem félkövérrel az új részeket. Ja és hogy mi az a fura megoldás a [ 1"$MOVE" = "11" ] sorban - ez azért van, mert a bash nem szereti, ha egy két operandusú feltételből hiányzik az egyik. Így tehát, amikor a $MOVE üres, az összehasonlítás így néz ki: 1 == 11 (tehát a feltétel nem igaz); ha pedig a $MOVE értéke 1, akkor 11 == 11 (tehát igaz). Ha nem így csinálnám, akkor üres $MOVE esetén a semmit hasonlítanánk az 1-gyel, amire a bash háklis.
 

Az elkészült kis szkript nyilván nem tud annyi mindent, mint a Dayfolder nevű program, és lehet hogy nem is annyira szép grafikus a felülete, és csak bash 3.x-szel használható, de remélem, adott pár ötletet.

2 komment

Címkék: linux hogyan rendezés egyszerű alkalmazások szkript fájl parancssor elfelejtett világ

süti beállítások módosítása