If-Koubou

Ghidul începătorului pentru Shell Scripting 2: For Loops

Ghidul începătorului pentru Shell Scripting 2: For Loops (Cum să)

Dacă doriți să vă construiți un geek cred, alăturați-ne pentru cea de-a doua tranșă din seria noastră de scripting shell. Avem câteva corecții, câteva îmbunătățiri ale scenariului de săptămâna trecută și un ghid despre looping pentru cei neinițiați.

Datacp Script Revisited

În prima parte a ghidului de scripting pentru shell, am făcut un script care a copiat un fișier într-un director de rezervă după ce a adăugat data până la sfârșitul numelui fișierului.

Samuel Dionne-Riel a subliniat în comentariile că există o modalitate mult mai bună de a ne ocupa de referințele noastre variabile.

Argumentele sunt separate în spațiu în shell-ul bash, acesta va tokenize când există un spațiu în comanda extinsă rezultată. În scenariul tău, cp $ 1 $ 2. $ data_formatted va funcționa conform destinației atâta timp cât variabilele extinse nu au spații în ele. Dacă numiți scenariul în felul următor: datecp "numele meu vechi" "noul meu nume" extinderea va avea ca rezultat această comandă: cp noul meu nume vechi name.the_date care are de fapt 6 argumente.

Pentru a aborda corect această problemă, ultima linie a scriptului ar trebui să fie: cp "$ 1" "$ 2. $ date_formatted"

După cum puteți vedea, schimbați linia scriptului nostru de la:

cp -iv $ 1 $ 2. $ date_formatted

la:

cp -iv "$ 1" "$ 2". $ date_formatted

va avea grijă de această problemă atunci când se utilizează script-ul pe fișiere care au spații în nume. De asemenea, Samuel subliniază faptul că atunci când copiați și inserați coduri de pe acest site (sau de internet în general), asigurați-vă că înlocuiți liniuțele și citatele potrivite pentru cele "tipografice mai bune" care le înlocuiesc adesea. De asemenea, vom face mai multe pentru a vă asigura că codul nostru este mai prietenos cu copierea / lipirea. ;-)

Un alt comentator, Myles Braithwaite, a decis să ne extindă scenariul, astfel încât data să apară înaintea extensiei fișierului. Deci, în loc de

tastyfile.mp3.07_14_11-12.34.56

am obține acest lucru:

tastyfile.07_14_11-12.34.56.mp3

care sfârșește prin a fi un pic mai convenabil pentru majoritatea utilizatorilor. Codul său este disponibil pe pagina GitHub. Să aruncăm o privire la ceea ce el folosește pentru a desprinde numele fișierului.

date_formatted = $ (data +% Y-% m-% d_% H.% M% S)
file_extension = $ (echo "$ 1" | awk -F. 'print $ NF')
file_name = $ (numele de bază $ 1. $ file_extension)

cp -iv $ 1 $ file_name- $ date_formatted. $ file_extension

Am schimbat puțin formatarea, dar puteți vedea că Myles își declară funcția de dată în Linia 1. În Linia 2, totuși, el folosește comanda "ecou" cu primul argument al scriptului pentru a ieși numele fișierului. El folosește comanda țeavă pentru a ține acea ieșire și o folosește ca intrare pentru următoarea parte. După țeavă, Myles apelează comanda "awk", care este un program puternic de scanare a modelelor. Folosind pavilionul -F, el spune comanda că următorul caracter (după un spațiu) este ceea ce va defini "separatorul de câmp". În acest caz, este o perioadă.

Acum, awk vedeți un fișier numit "tastyfile.mp3" ca fiind compus din două câmpuri: "tastyfile" și "mp3". În cele din urmă, el folosește

'print $ NF'

pentru a afișa ultimul câmp. În cazul în care fișierul dvs. are mai multe perioade - făcând astfel awk să vadă mai multe câmpuri - va afișa numai ultima, care este extensia de fișier.

În linia 3, el creează o nouă variabilă pentru numele fișierului și folosește comanda "basename" pentru a face referire la totul în $ 1 cu exceptia extensia de fișier. Acest lucru se face folosind numele de bază și dându-i $ 1 ca argument, apoi adăugând un spațiu și extensia fișierului. Extensia fișierului este adăugată automat din cauza variabilei care indică linia 2. Ce ar face acest lucru este să luați

tastyfile.mp3

și transformă-o în

tastyfile

Apoi, în ultimul rând, Myles a pus împreună comanda care va scoate totul în ordine. Rețineți că nu există nici o referință la $ 2, un al doilea argument pentru script. Acest script special va copia fișierul menționat în directorul dvs. curent. Marea treabă Samuel și Myles!

Rularea scripturilor și $ PATH

De asemenea, menționăm în articolul nostru de bază că script-urile nu au voie să fie menționate ca comenzi în mod implicit. Adică trebuie să indicați calea scenariului pentru al rula:

./script

~ / Bin / script

Dar, prin plasarea scripturilor în ~ / bin /, puteți să le introduceți numele de oriunde pentru a le face să ruleze.

Comenterii au petrecut ceva timp dezbătând cât de corect a fost acest lucru, deoarece nici un distro Linux modern nu creează acel director în mod implicit. În plus, nimeni nu îl adaugă implicit la variabila $ PATH, ceea ce este necesar pentru ca scripturile să fie executate ca și comenzi. Am fost puțin nedumerit, deoarece după ce am verificat variabila mea $ PATH, comentatorii au avut dreptate, dar scripturile de asteptare încă lucrau pentru mine. Am aflat de ce: multe distribuții moderne Linux creează un fișier special în directorul de domiciliu al utilizatorului - .profile.

Acest fișier este citit de bash (cu excepția cazului în care .bash_profile este prezent în directorul de domiciliu al utilizatorului), iar în partea de jos există o secțiune care adaugă directorul ~ / bin / la variabila $ PATH dacă există. Deci, acel mister este clarificat. Pentru restul seriei, voi continua să plasez script-uri în directorul ~ / bin /, deoarece acestea sunt scripturi de utilizator și ar trebui să poată fi gestionate de utilizatori. Și, se pare că nu avem nevoie de mers cu variabila $ PATH cu mâna pentru a face lucrurile să funcționeze.

Repetarea comenzilor cu buclă

Să ajungem la unul dintre cele mai utile instrumente din arsenalul geek pentru a face față sarcinilor repetate: bucle. Astăzi, vom discuta despre "buclele".

Schița de bază a for-buclă este după cum urmează:

pentru VARIABLE in LIST; do
command1
comanda2

commandn
Terminat

VARIABLE poate fi orice variabilă, deși cel mai adesea "i" este folosit convențional. LIST este o listă de articole; puteți specifica mai multe elemente (separându-le de un spațiu), indicați un fișier text extern sau utilizați un asterisc (*) pentru a indica orice fișier din directorul curent. Comenzile listate sunt indentate prin convenție, deci este mai ușor să vezi cuiburile - punerea buclelor în bucle (astfel încât să puteți bucla în timp ce faceți buclă).

Deoarece listele folosesc spațiile ca delimitatori - adică un spațiu înseamnă o mutare la următorul element din listă - fișierele care au spații în nume nu sunt foarte prietenoase. Pentru moment, să rămânem la lucru cu fișiere fără spații. Să începem cu un script simplu pentru a afișa numele fișierelor din directorul curent. Creați un script nou în folderul dvs. ~ / bin / intitulat "loopscript". Dacă nu vă amintiți cum să faceți acest lucru (inclusiv marcarea acestuia ca executabil și adăugarea hack-ului de tip hash), consultați articolul de bază despre bash scripting.

În acesta, introduceți următorul cod:

pentru i în item1 item2 item3 item4 item5 item6; do
echo "$ i"
Terminat

Când rulați scriptul, ar trebui să obțineți elementele listate ca ieșire.

Destul de simplu, nu? Să vedem ce se întâmplă dacă schimbăm puțin lucrurile. Schimbați-vă scenariul astfel încât să spuneți acest lucru:

pentru că eu în *; do
echo "$ i"
Terminat

Când executați acest script într-un dosar, trebuie să obțineți o listă de fișiere pe care le conține ca ieșire.

Acum, să schimbăm comanda ecou în ceva mai util - să zicem, comanda zip. Adică, vom adăuga fișiere într-o arhivă. Și, hai să luăm câteva argumente în mix!

pentru eu în $ @; do
arhiva zip "$ i"
Terminat

Este ceva nou! "$ @" Este o comandă rapidă pentru "$ 1 $ 2 $ 3 ... $ n". Cu alte cuvinte, este lista completă a tuturor argumentelor pe care le-ați specificat. Acum, urmăriți ce se întâmplă când rulez scriptul cu mai multe fișiere de intrare.

Puteți vedea fișierele din dosarul meu. Am executat comanda cu șase argumente și fiecare fișier a fost adăugat la o arhivă cu cifre numită "archive.zip". Ușor, nu?

Buclele sunt destul de minunate. Acum puteți executa funcții lot pe liste de fișiere. De exemplu, puteți să copiați toate argumentele scriptului într-o arhivă zip, să mutați originalele într-un alt folder și să copiați automat fișierul zip pe un computer la distanță. Dacă configurați fișiere cheie cu SSH, nici măcar nu trebuie să introduceți parola și chiar puteți spune scriptului să șterge fișierul zip după încărcarea lui!

Folosind for-buclele, este ușor să faci o grămadă de acțiuni pentru toate fișierele dintr-un director. Aveți posibilitatea să stivuiți o mare varietate de comenzi împreună și să folosiți argumentele foarte ușor pentru a crea și a-on-the-fly lista, și aceasta este doar vârful aisbergului.

Bash scripteri, aveți vreo sugestie? Ați făcut un script util care utilizează buclele? Doriți să vă împărtășiți gândurile seriei? Lăsați câteva comentarii și ajutați-i pe ceilalți începători de scripting!