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

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

A bejegyzés trackback címe:

https://bagojur.blog.hu/api/trackback/id/tr894513785

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

szucsjoee 2012.05.22. 23:23:34

nagyon kafa :D
alkalmazom is :)

atomgape 2012.06.05. 23:07:14

Ez tényleg ott van, köszi!
süti beállítások módosítása