Este destul de ușor să citiți conținutul unei linii de fișier text Linux pe linie într-un script de coajă - atâta timp cât vă ocupați de unele Gotchas subtile. Iată cum să o faceți în siguranță.
Fișiere, text și idiomuri
Fiecare limbă de programare are un set de idiomuri. Acestea sunt modalitățile standard, fără friză de a realiza un set de sarcini comune. Sunt modulele elementare sau implicite de a utiliza una dintre caracteristicile limbii cu care lucrează programatorul. Ele devin parte a unui set de plante al unui programator al planurilor mentale.
Acțiuni precum citirea datelor din fișiere, care lucrează cu bucle și schimbarea valorilor a două variabile sunt exemple bune. Programatorul va cunoaște cel puțin o modalitate de a-și atinge scopurile într-o manieră generică sau de vanilie. Poate că aceasta va fi suficientă pentru cerința la îndemână. Sau poate că vor împrăștia codul pentru ao face mai eficientă sau aplicabilă soluției specifice pe care le dezvoltă. Dar având idiomul blocului de clădiri la vârful degetelor este un punct de plecare mare.
Cunoașterea și înțelegerea idiomilor într-o singură limbă ușurează, de asemenea, să ridicați un nou limbaj de programare. Știind cum lucrurile sunt construite într-o singură limbă și căutând echivalentul - sau cel mai apropiat lucru - într-o altă limbă este o modalitate bună de a aprecia asemănările și diferențele dintre limbile de programare pe care le cunoașteți deja și cele pe care le aflați.
Citirea liniilor dintr-un fișier: One-Liner
În bash, puteți folosi a
in timp ce
buclă pe linia de comandă pentru a citi fiecare linie de text dintr-un fișier și faceți ceva cu el. Fișierul nostru text este numit "Data.txt". Acesta deține o listă a lunilor anului.
Ianuarie februarie Martie . . octombrie noiembrie Decembrie
Călătoria noastră simplă este:
în timp ce se citește linia; do ECHO $ linia; DONE & LT; Data.txt
În
in timp ce
Loopul citește o linie din fișier, iar fluxul de execuție al micului program trece la corpul bucla. În
ecou
Comanda scrie linia de text din fereastra terminalului. Încercarea de citire nu reușește atunci când nu mai există mai multe linii, iar bucla se face.
Un truc curat este abilitatea Pentru a redirecționa un fișier într-o buclă . În alte limbi de programare, ar trebui să deschideți fișierul, să citiți de la acesta și să îl închideți din nou când ați terminat. Cu bash, puteți pur și simplu să utilizați redirecționarea fișierelor și lăsați cochilia să se ocupe de toate lucrurile de nivel scăzut pentru tine.
Desigur, acest liniar nu este foarte util. Linux oferă deja deja
pisică
Comandă, care face exact asta pentru noi. Am creat o modalitate îndelungată de a înlocui o comandă de trei litere. Dar demonstrează vizibil principiile citirii dintr-un dosar.
Care funcționează destul de bine, până la un punct. Să presupunem că avem un alt fișier text care conține numele lunilor. În acest fișier, secvența de evacuare pentru un caracter nou a fost atașată la fiecare linie. O vom numi "Data2.txt."
Ianuarie \ n Februarie \ N. Martie \ n. . . Octombrie \ N. Noiembrie \ n. Decembrie \ n
Să folosim un singur fișier pe noul nostru fișier.
în timp ce se citește linia; do ECHO $ linia; DONE & LT; Data2.txt
Caracterul de evacuare din spate "
\
"A fost aruncată. Rezultatul este că un "N" a fost atașat la fiecare linie. Bash interpretează spatele ca începutul unui
Secvența de evacuare
. Adesea, nu vrem ca Bash să interpreteze ceea ce citește. Poate fi mai convenabil să citiți o linie în secvențele sale de evacuare în întregime și pe toate - și să alegeți ce să vă pariați sau să vă înlocuiți, în cadrul codului dvs. propriu.
Dacă vrem să facem o prelucrare semnificativă sau parsare pe liniile de text, va trebui să folosim un script.
Citirea liniilor dintr-un fișier cu un script
Iată scenariul nostru. Se numește "Script1.Sh".
#! / Bin / bash
Counter = 0
în timp ce IFS = ' Citiți -R Linefromfile [116 ] || [[ -N " $ {linefromfile} " ] ]; Do
(( ++ ))
ECHO "Linia de acces $ Counter : $ {linefromfile} " [9 ]
"" $ 1 "
Am stabilit o variabilă numită
Tejghea
la zero, atunci ne definim
in timp ce
buclă.
Prima declarație pe linia de timp este
Dacă = ''
.
Dacă
înseamnă separator de câmp intern. Acesta deține valori pe care le folosește Bash pentru a identifica limitele cuvintelor. În mod implicit, comenzile de citire se fixează pe spațiul alb de lideri și de sfârșit. Dacă vrem să citim liniile din fișier exact așa cum sunt, trebuie să stabilim
Dacă
a fi un șir gol.
Am putea stabili acest lucru o dată în afara buclei, la fel ca și cum vom stabili valoarea
Tejghea
. Dar cu scripturi mai complexe - în special cele cu multe funcții definite de utilizator în ele - este posibil ca
Dacă
ar putea fi setate la diferite valori în altă parte în script. Asigurarea faptului că
Dacă
este setat la un șir gol de fiecare dată
in timp ce
Buclele iterate garantează că știm ce va fi comportamentul său.
Vom citi o linie de text într-o variabilă numită
Linefromfile
. Folosim.
-R.
(Citiți backslash ca caracter normal) pentru a ignora backslashes. Ei vor fi tratați la fel ca orice alt personaj și nu vor primi niciun tratament special.
Există două condiții care vor satisface
in timp ce
buclă și permiteți ca textul să fie procesat de corpul bucla:
-
Citire -R linefromfile: Când o linie de text este citită cu succes din fișier,cititcomanda trimite un semnal de succes lain timp ce, siin timp ceBuclele transmite fluxul de execuție către corpul bucla. Rețineți căcititComanda trebuie să vadă a Caracterul Newline. La sfârșitul liniei de text pentru a considera că este vorba de succes. Dacă fișierul nu este a Posix. Fișier text compatibil, Ultima linie nu poate include un personaj nou . Dacăcititcomanda vede Sfârșitul markerului de fișiere (EOF) Înainte ca linia să fie terminată de o linie nouă, va nu tratați-l ca o citire reușită. Dacă se întâmplă acest lucru, ultima linie de text nu va fi transmisă corpului buclă și nu va fi procesată. -
[-N "$ {linefromfile}"]: Trebuie să facem câteva lucruri suplimentare pentru a gestiona fișierele compatibile non-POSIX. Această comparație verifică textul citit din fișier. Dacă nu este reziliat cu un personaj nou, această comparație va returna în continuare succesul lain timp cebuclă. Acest lucru asigură că orice fragmente de linie de tracțiune sunt prelucrate de corpul bucla.
Aceste două clauze sunt separate de operatorul sau logicului "
||.
"Deci, dacă
fie
Clauza returnează succesul, textul preluat este procesat de corpul bucla, fie că există sau nu un caracter nou.
În corpul bucla noastră, creștem
Tejghea
variabilă cu una și utilizarea
ecou
pentru a trimite o ieșire la fereastra terminalului. Numărul de linie și textul fiecărei linii sunt afișate.
Încă mai putem folosi truc de redirecționare pentru a redirecționa un fișier într-o buclă. În acest caz, redirecționăm 1 $, o variabilă care deține numele primului parametru linia de comandă care a trecut la script. Folosind acest truc, putem trece cu ușurință în numele fișierului de date pe care dorim scriptul să lucreze.
Copiați și lipiți scriptul într-un editor și salvați-l cu numele de fișier "Script1.sh". Folosește
chmod
comanda
pentru a face executabil
.
Chmod + X Script1.sh
Să vedem ce face scriptul nostru din fișierul text Data2Txt și backsashele conținute în el.
./ Script1.Sh Data2Txt
Fiecare caracter din linie este afișat verbatim. Backsashele nu sunt interpretate ca caractere de evadare. Sunt tipărite ca personaje regulate.
Trecând linia la o funcție
Încă mai avem doar textul pe ecran. Într-un scenariu de programare din lumea reală, probabil că vom face ceva mai interesant cu linia de text. În cele mai multe cazuri, este o practică bună de programare de a gestiona prelucrarea ulterioară a liniei într-o altă funcție.
Iată cum am putea face-o. Acesta este "Script2.Sh".
Ne definim
Tejghea
variabilă ca înainte, și apoi definim o funcție numită
proces_line ()
. Definiția unei funcții trebuie să apară
inainte de
Funcția este numită pentru prima dată în script.
Funcția noastră va fi transmisă linia de text recent în fiecare iterație a
in timp ce
buclă. Putem accesa acea valoare în cadrul funcției utilizând
$ 1.
variabil. Dacă au fost transmise două variabile la funcția, am putea accesa aceste valori folosind
$ 1.
și
$ 2.
, și așa mai departe pentru mai multe variabile.
W.
Hile.
bucla este în principal la fel. Există o singură schimbare în interiorul corpului buclă. În
ecou
linia a fost înlocuită cu un apel către
proces_line ()
funcţie. Rețineți că nu aveți nevoie să utilizați parantezele "()" în numele funcției atunci când îl sunați.
Numele variabilei care ține linia de text,
Linefromfile
, este înfășurat în ghilimele când este transmis funcției. Acest lucru se datorează liniilor care au spații în ele. Fără ghilimele, primul cuvânt este tratat ca
$ 1.
Prin funcție, cel de-al doilea cuvânt este considerat a fi
$ 2.
, si asa mai departe. Utilizarea ghilimele se asigură că întreaga linie de text este manipulată, cu totul, ca
$ 1.
. Rețineți că aceasta este
nu
la fel
$ 1.
care deține același fișier de date transmis scriptului.
pentru că
Tejghea
a fost declarată în corpul principal al scenariului și nu în interiorul unei funcții, acesta poate fi referit în interiorul
proces_line ()
funcţie.
Copiați sau introduceți scriptul de mai sus într-un editor și salvați-l cu numele de fișier "Script2.Sh". Face executabil cu
chmod
:
Chmod + X Script2.Sh
Acum putem să o conducem și să trecem într-un nou fișier de date, "Data3.txt." Aceasta are o listă a lunilor în el și o linie cu multe cuvinte pe ea.
Ianuarie februarie Martie . . octombrie Noiembrie \ mai mult text "la sfârșitul liniei" Decembrie
Comanda noastră este:
./ Script2.Sh Data3.txt
Liniile sunt citite din fișier și au trecut unul câte unul la
proces_line ()
funcţie. Toate liniile sunt afișate corect, inclusiv cele ciudate cu backspace, ghilimele și mai multe cuvinte în el.
Blocurile de construcție sunt utile
Există un tren de gândire care spune că un idiom trebuie să conțină ceva unic pentru acea limbă. Nu este o convingere că mă abonez. Ceea ce este important este că folosește bine limba, este ușor de reținut și oferă o modalitate fiabilă și robustă de a implementa anumite funcționalități în codul dvs.