2017. január 31., kedd

A kezdők útmutatója a shell scripteléshez 2: For ciklusok


Ha szeretnéd felépíteni a kocka hitelességedet, tarts velünk a scriptelős sorozatunk második részében. Van néhány javításunk, néhány fejlesztésünk az előző heti scripthez és egy útmutatónk a ciklusokhoz a beavatatlanok számára.

A Datecp script átvizsgálva

A scriptelős sorozunk első részében csináltunk egy scriptet, ami átmásolt egy fájlt egy biztonsági mentés könyvtárba, miután hozzáfűzte a dátumot a fájlnév végéhez.

Samuel Dionne-Riel rámutatott a hozzászólásokban, hogy van egy sokkal jobb módja is a változóink meghívásának kezelésére.

A paraméterek szóközzel vannak elválasztva a bash shellben, akkor működnek, ha van egy szóköz az eredményezett kiterjesztett parancsban. A scriptedben a cp $1 $2.$date_formatted addig működik terv szerint, ameddig a kiterjesztett változókban nincsenek szóközök. Ha ezen a módon hívod meg a scriptedet: datecp "my old name" "my new name" a kibővítés ezt a parancsot eredményezi: cp my new name my old name.the_date, ami igazából hat paraméterrel rendelkezik.
Hogy megfelelően címezd meg a dolgot, a scripted utolsó sorának így kellene kinéznie: cp "$1" "$2.$date_formatted"

Ahogy láthatod, scriptünk sorának megváltoztatása erről:

cp -iv $1 $2.$date_formatted

Erre:

cp -iv “$1” “$2”.$date_formatted

Megoldja ezt a problémát, amikor a scriptünket olyan fájlokon használjuk, amiknek szóközök vannak a nevükben. Samuel rámutatott arra is, hogy amikor kódokat másolunk és beillesztünk erről az oldalról (vagy az internetről általában), legyél biztos benne, hogy behelyettesíted a megfelelő gondolatjeleket és idézőjeleket a "nyomdailag jobb" változatokhoz, amik gyakran felcserélik őket. Mi is egyre többet teszünk azért, hogy a kódjaink jobban másolás/beillesztés barátak legyenek. ;-)

Egy másik hozzászóló, Myles Braithwaite, úgy döntött, hogy kibővíti a scriptünket, így a dátum a fájlkiterjesztés előtt jelenne meg. Így ehelyett:

tastyfile.mp3.07_14_11-12.34.56

Ezt kapnánk:

tastyfile.07_14_11-12.34.56.mp3

Ami egy kicsit több kényelmet eredményez a felhasználók többségének. A kódja elérhető a GitHub oldalán. Nézzük meg mit használ ahhoz, hogy kihúzza a fájlnevet.

date_formatted=$(date +%Y-%m-%d_%H.%M%S)
file_extension=$(echo “$1″|awk -F . ‘{print $NF}’)
file_name=$(basename $1 .$file_extension)
cp -iv $1 $file_name-$date_formatted.$file_extension

Megváltoztattam a formázást egy kicsit, de láthatod, hogy Myles az első sorban adja meg a dátum funkcióját. A második sorban azonban az "echo" parancsot használja a script első paraméterével a fájl nevének kimenetéhez. A pipe parancsot használja, hogy fogja a kimenetet és bemenetként használja a következő részhez. A Pipe után Myles meghívja az "awk" parancsot, ami egy erőteljes mintakereső program. Az -F jelző használatával megmondja a parancsnak, hogy a következő karakter (a szóköz után) az, ami meghatározza a "mezőelválasztó"-t. Ebben az esetben az egy pont.

Most az awk egy "tastyfile.mp3" nevű fájlt lát, ahogy két mezőből tevődik össze: "tastyfile" és "mp3". Végül a ‘{print $NF}’ -et használja arra, hogy megjelenítse az utolsó mezőt. Abban az esetben, ha a fájlod több pontot tartalmaz - mivel az awk parancs több mezőt képes látni - csak az utolsót fogja megjeleníteni, ami a fájlkiterjesztés.

A harmadik sorban létrehoz egy új változót a fájl nevéhez és a "basename" parancsot használja, hogy meghívjon mindent, ami az 1$-ban van, kivéve a fájlkiterjesztés. A fájlkiterjesztés automatikusan hozzáadásra kerül a változó miatt, ami meghívja a második sort. Amit ez tenne az az, hogy fogja a

tastyfile.mp3 -at

és átváltoztatja erre

tastyfile

Azután az utolsó sorban Myles összerakja a parancsot, ami mindent a megfelelő sorrendben fog kiadni. Figyeld meg, hogy nincs hivatkozás a $2-re, a script második paraméterére. Ez az egyéni script a megnevezett fájlt az aktuális könyvtárba másolja át helyette. Remek munka Samuel és Myles!

Scriptek futtatása és a $PATH

Megemlítettük az alapvető cikkünkben azt is, hogy a scripteket alapvetően nem lehet parancsként meghívni. Azaz a script elérhetési útvonalára kell mutatnod ahhoz, hogy futtasd:

./script~/bin/script

De a scriptjeid ~/bin/-be helyezésével csak beírhatod a nevüket bárhonnan, hogy futtasd őket.
A hozzászólók rászántak némi időt arra, hogy megtárgyalják, hogy ez mennyire megfelelő, mivel egyik modern Linux disztró sem hozza létre azt a könyvtárat. Továbbá egyik sem adja hozzá alapból a $PATH változóhoz sem, ami ahhoz szükséges, hogy a scripteket parancsszerűen futtassuk. Kissé zavart voltam, mert miután ellenőriztem a $PATH változómat, a hozzászólóknak igazuk volt, de a scriptek meghívása így is működött számomra. Megtaláltam miért: Sok modern Linux disztró létrehoz egy speciális fájlt a felhasználó home könyvtárában – .profile.


A fájlt beolvassa a bash (amíg a .bash_profile fájl jelen van a felhasználó home könyvtárában) és az alján van egy részleg, ami hozzáadja a ~/bin/ mappát a $PATH változóhoz, ha az létezik. Így ez a rejtély megoldódott. A sorozat hátralévő részében folytatom a scripet ~/bin/-be helyezését, mert ezek felhasználói scriptet és futtathatóknak kell lenniük a felhasználók által és úgy tűnik, hogy nem igazából kell babrálnunk a $PATH változóval kézzel, hogy működőképessé tegyük a dolgokat.

Parancsok ismétlése ciklusokkal

Térjünk rá az egyik leghasznosabb eszközre a kocka arzenálból az ismétlődő feladatok kezeléséhez:
ciklusok. Ma a "for" ciklusokat fogjuk megtárgyalni.

Az alapvető vázlata egy for ciklusnak az alábbi:

for VARIABLE in LIST; do
command1
command2

commandn
done

A VARIABLE lehet bármilyen változó, habár leggyakrabban a kisbetűs "i"-t használják megegyezés szerint. A LIST az elemek listája; megadhatsz több elemet (szóközzel elválasztva őket), mutathatsz egy külső szöveges fájlra, használhatsz egy csillagot (*), hogy kijelölj bármilyen fájlt az aktuális könyvtárban. A parancsok megegyezés szerint vannak behúzva, így könnyebb látni a felépítést - ciklusokat helyezni ciklusokra (így ciklusozhatsz miközben ciklusozol).

Mivel a listák szóközt használnak határolójelként - azaz egy szóköz kifejez egy lépést a következő elemre a listában - fájlok, amik szóközöket tartalmaznak a nevükben, nem igazán barátságosak. Egyelőre ragaszkodjunk a szóközök nélküli fájlokkal való munkához. Kezdjük egy egyszerű scripttel, ami kilistázza a fájlok neveit az aktuális könyvtárban. Csinálj egy új "loopscript" nevű scriptet a ~/bin/ mappádban. Ha nem emlékszel, hogy hogyan kell ezt csinálni (beleértve a végrehajthatóként való megjelölést és a hash durrantós hack hozzáadását), nézd meg a bash scriptelés alapok cikkünket.

Írd bele az alábbi kódot:

for i in item1 item2 item3 item4 item5 item6; do
echo “$i”
done



Ha futtatod a scriptet, csak meg kellene kapnod azokat az elemeket kimenetként.



Eléggé egyszerű, ugye? Nézzük meg, hogy mi történik, ha megváltoztatjuk a dolgokat egy kicsit.
Változtasd meg a scripteted úgy, hogy ezt fejezze ki:

for i in *; do
echo “$i”
done


Amikor ezt a scriptet egy mappában futtatod, meg kellene kapnod a benne lévő fájlok listáját kimenetként.


Most cseréljük az echo parancsot valami hasznosabbra – mondjuk a zip parancsra.
Ugyanis fájlokat fogunk hozzáadni egy archívumhoz. Most pedig tegyünk néhány paramétert a keverékbe!

for i in $@; do
zip archive “$i”
done


Van itt valami új! A "$@" egy rövidítés a "$1 $2 $3...$n"-hez. Más szavakkal ez az általad megadott összes paraméter teljes listája. Most nézd meg mi történik, amikor futtatom ezt a scriptet néhány bemeneti fájllal.


Láthatod melyik fájlok vannak a mappámban. Futtattam a parancsot 6 paraméterrel és minden fájl hozzá lett adva egy "archive.zip" nevű zippelt archívumhoz. Könnyű, igaz?

A for ciklusok meglehetősen csodálatosak. Most már alkalmazni tudsz kötegelt funkciókat fájlok listáin. Például bemásolhatod a scripjeid összes paraméterét egy zippel archívumba, áthelyezheted az eredetiket egy másik mappába és automatikusan biztonságosan másolhatod a zip fájlt egy távoli számítógépre. Ha beállítod a kulcs fájlokat SSH-val, többé be sem kell írnod a jelszavadat és megmondhatod a scriptnek, hogy törölje a zip fájlt feltöltés után!

A for ciklusok használata megkönnyíti műveletek sokaságának elvégzését minden fájlon egy könyvtárban. Összerakhatod parancsok széles választékát és használhatsz paramétereket nagyon könnyedén, hogy létrehozz egy menet közbeni listát és ez csak a jéghegy csúcsa.

Bash scriptelők, van bármilyen javaslatotok? Csináltál egy hasznos scriptet, ami ciklusokat használ? Meg szeretnéd osztani a sorozattal kapcsolatos gondolataidat? Hagyj néhány hozzászólást és segíts ki más kezdő scriptelőket!

Felhasznált forrás: The Beginner's Guide to Shell Scripting 2: For Loops

Nincsenek megjegyzések:

Megjegyzés küldése