În anumite situații, este necesar să executați o serie de comenzi Linux, dar se întâmplă ca una dintre ele să nu accepte date transmise prin pipe? Instrumentul `xargs` vine în ajutor, preluând rezultatul unei comenzi și folosindu-l ca argumente pentru o altă comandă.
Toate utilitarele Linux standard sunt asociate cu trei fluxuri de date. Acestea sunt: fluxul de intrare standard (stdin), fluxul de ieșire standard (stdout) și fluxul de erori standard (stderr).
Aceste fluxuri funcționează cu date textuale. Transmitem date (stdin) unei comenzi sub formă de text, iar rezultatul (stdout) este afișat în fereastra terminalului tot ca text. Mesajele de eroare sunt, de asemenea, afișate în terminal ca text (stderr).
O caracteristică importantă a sistemelor de operare Linux și Unix este abilitatea de a redirecționa fluxul stdout de la o comandă către fluxul stdin al altei comenzi. Prima comandă nu se preocupă de faptul că rezultatul său nu este afișat în terminal, iar cea de-a doua comandă nu se preocupă de faptul că datele de intrare nu vin de la tastatură.
Deși toate comenzile Linux dispun de cele trei fluxuri standard, nu toate acceptă fluxul stdout al unei alte comenzi ca intrare în fluxul lor stdin. Asta înseamnă că nu poți pur și simplu să le trimiți date.
`xargs` este un instrument destinat construirii unor lanțuri de execuție, folosind fluxurile de date standard. Cu `xargs`, putem permite unor comenzi precum `echo`, `rm` și `mkdir` să accepte datele standard ca argumente.
Funcționalitatea comenzii `xargs`
`xargs` procesează date de intrare primite prin pipe. De asemenea, poate accepta date dintr-un fișier. Aceste date sunt folosite ca parametri pentru comenzile specificate. Dacă nu este specificată o comandă, `xargs` va folosi implicit `echo`.
Putem demonstra modul în care `xargs` generează o singură linie de ieșire, chiar dacă primește date de intrare pe mai multe linii.
Folosind opțiunea `-1` (listarea unui fișier pe linie) cu `ls`, obținem o coloană verticală cu numele fișierelor.
ls -1 ./*.sh
Aceasta afișează fișierele script shell din directorul curent.
Obținem o singură coloană, conform așteptărilor. Dacă transmitem această ieșire prin `xargs`, ce obținem?
ls -1 ./*.sh | xargs
Rezultatul este afișat în fereastra terminalului ca un singur șir de text.
Această capacitate ne permite să transmitem parametri către alte comenzi.
Utilizarea `xargs` cu `wc`
Putem folosi `xargs` pentru a permite comenzii `wc` să numere ușor cuvintele, caracterele și rândurile din mai multe fișiere.
ls *.page | xargs wc
Iată ce se întâmplă:
`ls` listează fișierele `*.page` și transmite lista către `xargs`.
`xargs` transmite numele fișierelor către `wc`.
`wc` tratează numele fișierelor ca și cum ar fi primite ca parametri direct din linia de comandă.
Statisticile pentru fiecare fișier sunt afișate împreună cu un total general.
Utilizarea `xargs` cu confirmare
Putem folosi opțiunea `-p` (interactivă) pentru ca `xargs` să ne ceară confirmarea înainte de a continua.
Dacă transmitem o listă de nume de fișiere către `touch`, prin intermediul `xargs`, `touch` va crea fișierele pentru noi.
echo 'one two three' | xargs -p touch
Comanda care urmează să fie executată este afișată, iar `xargs` așteaptă un răspuns. Trebuie să tastăm „y” sau „Y” pentru a continua, sau „n” sau „N” pentru a anula, și să apăsăm Enter.
Dacă apăsăm Enter, acesta este interpretat ca „n”. Comanda este executată numai dacă tastăm „y” sau „Y”.
Am apăsat „y” și am apăsat Enter. Putem folosi `ls` pentru a verifica dacă fișierele au fost create.
ls one two three
Utilizarea `xargs` cu mai multe comenzi
Putem folosi mai multe comenzi cu `xargs` utilizând opțiunea `-I` (argumente inițiale).
Această opțiune definește un „șir de înlocuire”. Oriunde apare simbolul pentru șirul de înlocuire în linia de comandă, sunt inserate valorile transmise de `xargs`.
Să folosim comanda `tree` pentru a vizualiza subdirectoarele din directorul curent. Opțiunea `-d` (director) face ca `tree` să ignore fișierele și să afișeze numai directoarele.
tree -d
Există un singur subdirector numit „imagini”.
Într-un fișier numit `directories.txt`, avem o listă cu numele directoarelor pe care dorim să le creăm. Putem vizualiza conținutul folosind `cat`.
cat directories.txt
Vom folosi acest fișier ca date de intrare pentru `xargs`. Iată comanda pe care o vom executa:
cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'
Aceasta se descompune astfel:
`cat directories.txt |`: Această comandă transmite conținutul fișierului `directories.txt` (toate noile nume de directoare) către `xargs`.
`xargs -I %`: Această comandă definește un „șir de înlocuire” cu simbolul „%”.
`sh -c`: Această comandă pornește un subshell nou. `-c` (comandă) îi spune shell-ului să citească comenzile din linia de comandă.
`’echo %; mkdir %’`: Fiecare simbol „%” va fi înlocuit cu numele directorului transmis de `xargs`. Comanda `echo` va afișa numele directorului, iar comanda `mkdir` va crea directorul.
Directoarele sunt listate unul câte unul.
Putem folosi `tree` încă o dată pentru a verifica dacă directoarele au fost create.
tree -d
Copierea fișierelor în mai multe locații
Putem folosi `xargs` pentru a copia fișiere în mai multe locații dintr-o singură comandă.
Vom introduce numele a două directoare în `xargs` ca parametri de intrare. Vom specifica ca `xargs` să transmită câte un parametru o dată către comanda cu care lucrează.
În acest caz, comanda este `cp`. Efectul este de a apela `cp` de două ori, de fiecare dată cu unul dintre cele două directoare ca parametru. Parametrul `xargs` care permite acest lucru este opțiunea `-n` (număr maxim). Vom seta această valoare la unu.
Folosim, de asemenea, opțiunea `-v` (verboasă) cu `cp` pentru a vedea ce se întâmplă.
echo ~/Backups/ ~/Documents/page-files/ | xargs -n 1 cp -v ./*.page
Fișierele sunt copiate în cele două directoare, câte un director pe rând. `cp` raportează fiecare acțiune de copiere, pentru a putea vedea ce se întâmplă.
Ștergerea fișierelor din directoare imbricate
Dacă numele fișierelor conțin spații și caractere speciale – cum ar fi caracterele de linie nouă – `xargs` nu le va putea interpreta corect. Putem depăși această problemă folosind opțiunea `-0` (terminator nul). Această opțiune îi spune lui `xargs` să folosească caracterul nul ca delimitator final pentru numele fișierelor.
Vom folosi `find` în acest exemplu. `find` are propria opțiune pentru a gestiona spațiile albe și caracterele speciale din numele fișierelor. Aceasta este opțiunea `-print0` (nume complet, caracter nul).
find . -name "*.png" -type f -print0 | xargs -0 rm -v -rf "{}"
Această comandă se descompune astfel:
`find . -name „*.png”`: `find` va căuta în directorul curent `.` obiectele cu nume care se potrivesc cu `*.png`, care sunt fișiere (`-type f`).
`-print0`: Numele fișierelor vor fi terminate cu un caracter nul, iar spațiile și caracterele speciale vor fi luate în considerare.
`xargs -0`: `xargs` va considera, de asemenea, că numele fișierelor sunt terminate în nul, iar spațiile și caracterele speciale nu vor cauza probleme.
`rm -v -rf „{}”`: `rm` va fi detaliat și va raporta ce se întâmplă (`-v`). Va fi recursiv (`-r`), va căuta în subdirectoarele imbricate și va elimina fișierele fără a cere confirmare (`-f`). `{}` este înlocuit cu fiecare nume de fișier.
Toate subdirectoarele sunt cercetate, iar fișierele care se potrivesc cu modelul de căutare sunt șterse.
Eliminarea directoarelor imbricate
Să presupunem că dorim să eliminăm un set de subdirectoare imbricate. `tree` ne permite să le vedem.
tree -d
find . -name "level_one" -type d -print0 | xargs -0 rm -v -rf "{}"
Această comandă va folosi `find` pentru a căuta recursiv în directorul curent. Căutarea vizează un director numit „level_one”. Numele directoarelor sunt transmise prin `xargs` la `rm`.
Singurele diferențe semnificative între această comandă și comanda anterioară sunt că termenul de căutare este numele directorului de nivel superior, și că `-type d` îi spune comenzii `find` să caute directoare, nu fișiere.
Numele fiecărui director este afișat pe măsură ce este eliminat. Putem verifica cu comanda `tree`:
tree -d
Toate subdirectoarele imbricate sunt șterse.
Ștergerea tuturor fișierelor, cu excepția unui tip de fișier
Putem folosi `find`, `xargs` și `rm` pentru a șterge toate fișierele, cu excepția unuia pe care dorim să-l păstrăm. Este ușor contraintuitiv, dar vom oferi numele tipului de fișier pe care dorim să-l păstrăm, nu numele celor pe care dorim să le ștergem.
Opțiunea `-not` îi spune lui `find` să returneze numele fișierelor care nu se potrivesc cu modelul de căutare. Folosim opțiunea `-I` (argumente inițiale) cu `xargs` încă o dată. De data aceasta, simbolul de înlocuire pe care îl definim este `{}`. Acesta se va comporta exact la fel ca simbolul de înlocuire șir pe care l-am generat anterior, care era `%`.
find . -type f -not -name "*.sh" -print0 | xargs -0 -I {} rm -v {}
Putem verifica cu `ls`. Singurele fișiere rămase în director sunt cele care se potrivesc cu modelul de căutare `*.sh`.
ls -l
Crearea unui fișier arhivă cu `xargs`
Putem folosi `find` pentru a căuta fișiere și a le transmite prin `xargs` la `tar`, pentru a crea un fișier de arhivă.
Vom căuta în directorul curent. Modelul de căutare este `*.page`, deci vom căuta fișiere `.page`.
find ./ -name "*.page" -type f -print0 | xargs -0 tar -cvzf page_files.tar.gz
Fișierele sunt listate conform așteptărilor, pe măsură ce fișierul arhivă este creat.
Mediatorul de date
Uneori, este necesară o legătură între comenzi. `xargs` realizează o punte între comenzile care pot furniza informații și comenzile care nu sunt create pentru a le primi direct.
Atât `xargs`, cât și `find` au un număr mare de opțiuni. Vă încurajăm să consultați paginile lor de manual pentru a afla mai multe.