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

Bash szkriptelés - sok fájl átnevezése, szóköz kezeléssel

2008.07.18. 11:36 bagoj ur

 

Atomgape kérése volt:

Na akkor most figyelj: kéne nekem egy script, amivel egy könyvtárban vagy könyvtárszerkezetben tömeges átnevezést tudok csinálni. Azaz mondjuk sok ilyen fájlnevem van:

Snoop Dogg - 01 - Bathtub -source.mp3
Snoop Dogg - 02 - Doggy Dogg World (feat. Tha Dogg Pound and The Dramatics) -source.mp3
(...)

Jó lenne, ha ki tudnám szedni a "-source" részt a végéről és a "Snoop Dogg - " részt az elejéről. Próbálkoztam, de a szóközök mindig kifogtak rajtam, így egyesével kell átneveznem.

Az egysoros megoldás erre a problémára szinte túl könnyű:

find ~ -name '* *' | while read F; do mv "$F" "$(echo $F | sed s/\-source//g)"; doneA gépházban eközben egy rakás fogaskerék kapcsolódik egymásba, miközben az is újfent kiderül, hogy a felhasználóbarát felülethez nem elsődlegesen fontos a grafikus interfész, valamint az átnevezés elvégzéséhez egyetlen animált gifet sem kellett megmozgatni. Ez sokak számára igen sajnálatos... hogy kicsit magyarázzak:

  • A find paranccsal (ezzel kapcsolatban valszeg nem kell közvélemény-kutatás) fájlokat lehet keresni. A trükk a keresősztringben van, ahol nem egyszerűen '*'-ra, hanem a szóközzel elválasztott szavakra keresünk. A mohó mintaillesztés miatt ez fog illeszkedni mindenre, amiben van legalább egy szóköz. Ha olyanokra is akarunk illeszteni, ahol nincs szóköz, akkor ez egy új sor lesz, ezúttal '*' paraméterrel (!).
  • A find parancs eredményét egy while ciklusba öntjük bele (a bash beépített függvénye), ahol a $F változóban találjuk az aktuális fájlnevet. Erre tehát elvégezzük az mv (átnevezés) parancsot: az eredeti fájlnevet olyanra cseréljük, ahol kivágtuk a "-source" karaktersort.
  • A sed paraméterei között az első "s" a substitute (helyettesítés), aztán a megfelelő szintaxissal megadjuk, hogy mit mire (jelen esetben üres sztringre).

 Mai rohanó, globalizálódó világunkban ;-) nem fogunk egy ennyire egy célra használható megoldással megelégedni: általánosítsuk tehát a problémát! Az első rögtön az, hogy a find-dal nem kereshetünk kétszer egymás után, hiszen akkor előfordulhat, hogy kétszer hozzábővítünk vagy elveszünk; egyetlen megoldás hogy egy sorban írjuk meg a szóközöket tartalmazó és nem tartalmazó kereső sort. Még jó, hogy a find-nak van -regex kapcsolója...

#!/bin/bash

# Bagoj ur tomeges fajl atnevezoje :)
# Hasznalat: massmv <könyvtár> mit mire

if [ $# = 3 ]; then
    MYDIR=$1
    MIT=$2
    MIRE=$3
else
    if [ $# = 2 ]; then
        MYDIR="."
        MIT=$1
        MIRE=$2
    else
        echo "Hasznalat: $0 <könyvtár> mit mire"
        exit 0
    fi
fi

if [ -d "$MYDIR" ]; then
    find "$MYDIR" -regex '.*' | while read F; do
        if [ -f "$F" ]; then
            NEWNAME=$(echo $F | sed "s/$MIT/$MIRE/g")
            mv "$F" "$NEWNAME"
        fi
    done
else
    echo "A megadott könyvtár nem megfelelő"
    exit 0
fi
Nem teszteltem, csak fejben bizonyítottam a működést... Ha csak két paramétert adok meg, akkor az aktuális könyvtárban és alatta keres; ha megadok, akkor abban.

UPDATE: Kicsit a kezelésről, meg a működésről. Ugye a $# a parancssori paraméterek számát adja vissza, annak megfelelően beállítjuk a MYDIR, MIT és MIRE értékeket. Megnézzük, hogy a MYDIR valóban könyvtár-e, majd a könyvtáron belül a find-dal összegyűjtött fájlokon megyünk egyesével végig. A NEWNAME változóba tesszük be azt, amire cseréljük a fájlnevet, majd az mv paranccsal megcsináljuk az átnevezést.

A használatnál arra kell vigyázni, hogy escape-elni azért kell, tehát a szóközt, pontot, mindenféle zárójeleket bevezető visszaper-jellel kell megadni. Pl:

massmv /usr/zene/pop "\ " "_"

Ez a szóközöket aláhúzás-jelekre cseréli ki.

 

6 komment

Címkék: keresés file script szkript átnevezés parancssor

A bejegyzés trackback címe:

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

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.

atomgape 2008.07.21. 12:47:20

Köszi szépen, tesztelem ha hazaértem!

atomgape 2008.08.13. 14:53:47

Leteszteltem, király! :-)

Celtic 2009.11.23. 21:31:37

Hopp, remelem, van otleted nekem is :)
Hasonlo problema, mint a fenti, csak en tobb fileban szeretnek egy sort cserelni.
ELso otlet:
grep -r keresem * | awk '{print $}' > tmpfile
while read ; do cat $REPLY ; done < tmpfile

Ez ugye visszadna "tmpfile"-ban azon file-ok neveit, amiben benne van a "keresem" szo, maosidk sor pedig elolvasna ezeket a file-okat.(Nem az, amit en akarok, de ezen konnyebben mutatom). Es itt jon a bibi: a filenevek szokozt tartalmaznak . Tobb probam is volt:
grep -r keresem * | awk '{print $}' | sed '/\ /\\/g' > tmpfile
a tmpfileban gyonyoru:
xx/yy/file\ neve
De ha ugyanezt beolvastatom a "while read" paranccsal, valami ertelmezi a "\" jelet es eltunteti :(

Valami otlet? Persze, megcsinalhatnam, hogy mondjuka "detox" proggival eltuntetem az osszes szokozt es ugy futtatom, csak sajnos ezek a file-ok havonta frissulnek :(

Celtic 2009.11.24. 09:09:12

Kozben a HUP-on meg is oldottak, a $REPLY-t idezojel koze kell tenni es mar jo is....
"$REPLY" a helyes...

bagoj ur 2009.11.24. 09:57:42

@Celtic: Szia, látod a HUPon este indul meg az élet. :) Ettől függetlenül tudnék javítani a kódon, a grep -l paramétere csak a fájlnevet írja ki, azaz nincs szükség awk-ra és sed-re:

grep -rl keresem * > tmpfile

Másik dolog, ami értelmes, a -Z paraméter; de nem lövöm le egyik következő írásom poénját. :)

Celtic 2009.11.24. 11:59:03

@bagoj ur: Ah, kosz, jol jon :) Mindig inkabb a filenevet igyekeztem elhagyni (-h), most meg csak a filenev kellene, de nem talaltam a kapcsolot.
Koszi!