Pentru a crea un nou director în directorul curent folosim comanda mkdir
.
student@uso:~/.../basics/toddler-s bottle/passcode$ cd ~/uso.git/labs/01-fs/support/basics student@uso:~/.../01-fs/support/basics$ ls grotesque 'hacker-s secret' rookiss 'toddler-s bottle' student@uso:~/.../01-fs/support/basics$ mkdir my-new-folder student@uso:~/.../01-fs/support/basics$ ls grotesque 'hacker-s secret' my-new-folder rookiss 'toddler-s bottle'
În cazul în care vrem să creăm un director al cărui nume conține spații, avem 2 posibilități.
Varianta 1:
student@uso:~/.../01-fs/support/basics$ mkdir "weird directory" student@uso:~/.../01-fs/support/basics$ ls grotesque my-new-folder 'toddler-s bottle' 'hacker-s secret' rookiss 'weird directory'
Varianta 2:
student@uso:~/.../01-fs/support/basics$ mkdir weird\ directory\ 2 student@uso:~/.../01-fs/support/basics$ ls grotesque my-new-folder 'toddler-s bottle' 'weird directory 2' 'hacker-s secret' rookiss 'weird directory'
Intrați în primul director creat. Vrem să creăm un fișier cu conținutul “Hello, world”.
student@uso:~/.../01-fs/support/basics$ cd w<TAB> student@uso:~/.../support/basics/weird directory$ echo "Hello, world" > my_file.txt student@uso:~/.../support/basics/weird directory$ ls -l total 4 -rw-r--r-- 1 student student 13 aug 21 22:59 my_file.txt
Până a trece mai departe, trebuie să vă asigurați că ați înțeles cum puteți crea noi fișiere și directoare. Pentru asta, parcurgeți următoarele exerciții după care verificați cu asistentul că totul este în regulă. Recomandăm folosirea paginii de manual pentru utilitarul ls
(man ls
). Vă va da informații despre toate argumentele pe care le puteți da comenzii ls
.
weird directory
. Creați directorul cu numel third weird directory
la calea basics/toddler-s\ bottle
. Mutați-vă la acea cale.my_second_file.txt
.cat
. Puteți folosi orice editor de text doriți pentru face modificări asupra fișierului.
Pentru a redenumi un fișier folosim comanda mv
. Comanda mv
are formatul mv sursă destinație
. În cazul în care uitați, folosiți pagina de manual a acesteia.
student@uso:~/.../basics/toddler-s bottle/third weird directory$ cd ~/uso.git/labs/01-fs/support/basics/toddler-s\ bottle student@uso:~/.../support/basics/toddler-s bottle$ ls bof fd input random collision flag passcode 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ mv collision my-new-collision student@uso:~/.../support/basics/toddler-s bottle$ ls bof flag my-new-collision random fd input passcode 'third weird directory'
Bineînțeles, putem redenumi un fișier aflat într-un alt director.
student@uso:~/.../support/basics/toddler-s bottle$ cd ~/uso.git/labs/01-fs/support/basics/toddler-s\ bottle student@uso:~/.../support/basics/toddler-s bottle$ ls ../grotesque/do\ you\ dare/ ascii dos4fun elf hunter hunting mipstake rootkit student@uso:~/.../support/basics/toddler-s bottle$ mv ../grotesque/do\ you\ dare/mipstake ../grotesque/do\ you\ dare/mistake student@uso:~/.../support/basics/toddler-s bottle$ ls ../grotesque/do\ you\ dare?/ ascii dos4fun elf hunter hunting mistake rootkit
Folosim tot comanda mv
pentru a muta un fișier într-un alt director.
student@uso:~/.../support/basics/toddler-s bottle$ ls bof flag my-new-collision random fd input passcode 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ ls ../hacker-s\ secret/ hard medium 'really hard' student@uso:~/.../support/basics/toddler-s bottle$ mv my-new-collision ../hacker-s\ secret/ # păstrand numele student@uso:~/.../support/basics/toddler-s bottle$ ls bof fd flag input passcode random 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ ls ../hacker-s\ secret/ hard medium my-new-collision 'really hard'
Există posibilitatea să mutăm un fișier într-un alt director și să-i schimbăm numele în același timp.
student@uso:~/.../support/basics/toddler-s bottle$ ls bof fd flag input passcode random 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ ls ../hacker-s\ secret/ hard medium my-new-collision 'really hard' student@uso:~/.../support/basics/toddler-s bottle$ mv flag ../hacker-s\ secret/my-new-flag # schimbând numele student@uso:~/.../support/basics/toddler-s bottle$ ls bof fd input passcode random 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ ls ../hacker-s\ secret/ hard medium my-new-collision my-new-flag 'really hard'
În cazul în care avem mai multe fișiere de mutat într-un alt (același) director, folosim tot comanda mv
.
student@uso:~/.../support/basics/toddler-s bottle$ ls bof fd input passcode random 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ ls ../rookiss/ 'ascii easy.pdf' echo2 loveletter syscall 'brain fuck' fix.pdf otp.pdf student@uso:~/.../support/basics/toddler-s bottle$ mv fd input ../rookiss student@uso:~/.../support/basics/toddler-s bottle$ ls bof passcode random 'third weird directory' student@uso:~/.../support/basics/toddler-s bottle$ ls ../rookiss 'ascii easy.pdf' echo2 fix.pdf loveletter syscall 'brain fuck' fd input otp.pdf
Până a trece mai departe în cadrul acestei secțiuni, trebuie să ne asigurăm că ați înțeles cum funcționează comanda mv
. Rezolvați exercițiile următoare până să treceți mai departe. Consultați-vă cu asistentul pentru orice nelămurire.
grotesque/asg
în directorul grotesque/do\ you\ dare/
din locul în care vă aflați.elf
hunter
mistake
din directorul grotesque/do\ you\ dare/
în directorul părinte al acestora.hacker-s\ secret
și mutați directorul hard
în directorul home al utilizatorului curent.toddler-s\ bottle/bof/easy
. Mutați în directorul basics
toate fișierele ale căror nume încep cu bof
și se termină cu .txt
. (Hint: wildcards)
Pentru a redenumi un fișier am văzut că folosim comanda mv
. În cazul în care vrem ca noul nume să conțină spații, procedăm ca mai devreme (vezi crearea directoarelor).
student@uso:~/.../toddler-s bottle/bof/easy$ cd ~/uso.git/labs/01-fs/support/basics student@uso:~/.../01-fs/support/basics$ ls bof1.txt bof4.txt 'hacker-s secret' 'toddler-s bottle' bof2.txt bof5.txt my-new-folder 'weird directory' bof3.txt grotesque rookiss 'weird directory 2' student@uso:~/.../01-fs/support/basics$ mv rookiss/ "my new rookiss" student@uso:~/.../01-fs/support/basics$ ls bof1.txt bof4.txt 'hacker-s secret' 'toddler-s bottle' bof2.txt bof5.txt my-new-folder 'weird directory' bof3.txt grotesque 'my new rookiss' 'weird directory 2'
Putem întâlni sitația în care vrem să redenumim un fișier al cărui nume conține deja spații, acestea trebuie escapate ca mai devreme. Putem scrie numele între ghilimele, însă există riscul să greșim în cazul numelor complicate și lungi. Cel mai sigur și ușor este să abuzăm de tasta <TAB> pentru a fi siguri că nu greșim. Vrem să modificăm numele directorului weird directory
în weird directory again
.
student@uso:~/.../01-fs/support/basics$ mv w<TAB> "weird directory again" student@uso:~/.../01-fs/support/basics$ ls bof1.txt bof4.txt 'hacker-s secret' 'toddler-s bottle' bof2.txt bof5.txt my-new-folder 'weird directory 2' bof3.txt grotesque 'my new rookiss' 'weird directory again'
Până a trece mai departe, trebuie să ne asigurăm că ați reținut cum trebuie lucrat în cazul în care avem de-a face cu nume de fișiere/directoare care conțin spații. Până să treceți la următoarea secțiune, parcurgeți următoarele exerciții și consultați-vă cu asistentul.
toddler-s\ bottle/passcode/random-org
în directorul curent fără a naviga către acel fișier. (Hint: directorul curent este .
)toddler-s\ bottle/bof/hard
în directorul home al utilizatorului curent fără a schimba directorul curent. (Hint: man cp
)
Ne-a rămas o singură comandă de bază despre care nu am vorbit, ștergerea. Pentru a șterge un fișier, folosim comanda rm
. Înainte să
student@uso:~/.../01-fs/support/basics$ cd ~/uso.git/labs/01-fs/support/basics/grotesque coin2 'do you dare' elf hunter mistake student@uso:~/.../support/basics/grotesque$ rm coin2 student@uso:~/.../support/basics/grotesque$ ls 'do you dare' elf hunter mistake
Avem posibilitatea de a șterge fișiere multiple folosind o singură comandă. Pentru asta, va trebui să pasăm ca argument comenzii toate fișierele pe care dorim să le ștergem.
student@uso:~/.../support/basics/grotesque$ cd ~/uso.git/labs/01-fs/support/basic/toddler-s\ bottle/bof/easy student@uso:~/.../toddler-s bottle/bof/easy$ ls bof-bof-bof can-you-bof random-bof.txt student@uso:~/.../toddler-s bottle/bof/easy$ rm bof-bof-bof can-you-bof student@uso:~/.../toddler-s bottle/bof/easy$ ls random-bof.txt
Ne aflăm în directorul ~/uso.git/labs/01-fs/support/basics/grotesque
și vrem să ștergem un fișier dintr-un alt director fără a schimba directorul în care ne aflăm. Putem face acest lucru ușor dându-i comenzii rm
calea către acel fișier (fie absolută, fie relativă).
student@uso:~/.../support/basics/grotesque$ ls 'do you dare' elf hunter mistake student@uso:~/.../support/basics/grotesque$ rm ../toddler-s\ bottle/bof/medium/getting-serious-here student@uso:~/.../support/basics/grotesque$ ls ../toddler-s\ bottle/bof/medium student@uso:~/.../support/basics/grotesque$
În cazul în care vrem să ștergem un întreg director, comanda rm <nume_director>
nu va funcționa. Trebuie să îi precizăm că vrem să ștergem recursiv toate fișierele și subdirectoarele din aceasta ierarhie. Pentru acest lucru, folosim argumentul -r
al comenzii rm
.
Dacă directorul pe care vrem să-l ștergem este gol, putem folosi și
comanda rmdir
.
student@uso:~/.../support/basics/grotesque$ cd ~/uso.git/labs/01-fs/support/basics student@uso:~/.../01-fs/support/basics$ ls bof1.txt bof5.txt 'my new rookiss' 'weird directory again' bof2.txt grotesque random-org bof3.txt 'hacker-s secret' 'toddler-s bottle' bof4.txt my-new-folder 'weird directory 2' student@uso:~/.../01-fs/support/basic$ rm -r "weird directory again" student@uso:~/.../01-fs/support/basic$ ls bof1.txt bof4.txt 'hacker-s secret' random-org bof2.txt bof5.txt my-new-folder 'toddler-s bottle' bof3.txt grotesque 'my new rookiss' 'weird directory 2' student@uso:~/.../01-fs/support/basic$ rmdir weird\ directory\ 2/ student@uso:~/.../01-fs/support/basic$ ls bof1.txt bof4.txt 'hacker-s secret' random-org bof2.txt bof5.txt my-new-folder 'toddler-s bottle' bof3.txt grotesque 'my new rookiss'
Pentru a vă asigura că ați înțeles cum se șterg fișierele și directoarele dintr-o ierarhie, parcurgeți următoarele exerciții și consultați-vă cu asistentul în cazul oricărei nelămuriri.
my new rookiss
și ștergeți fișierul syscall
.loveletter
și input
folosind o singură comandă.random-org
din directorul părinte.really hard
din hacker-s secret
.toddler-s\ bottle/bof/hard
..txt
din directorul toddler-s\ bottle/bof/easy
.basics
.Mai departe vom căuta în interiorul fișierelor dintr-o ierarhie. Vom folosi utilitarul grep. Acesta se folosește astfel:
student@uso:~/uso.git$ grep --help Usage: grep [OPTION]... PATTERN [FILE]... Search for PATTERN in each FILE. Example: grep -i 'hello world' menu.h main.c
Cuvântul cheie grep urmat de opțiuni și de cuvântul cheie pe care îl căutam. Putem afla aceste opțiuni prin folosirea comenzii man grep sau grep –help la fel ca la utilitarul locate. Astfel, putem observa că există opțiunea -r cu care putem căuta recursiv intr-o ierarhie de fișiere.
Vrem să căutam apariția int main()
in ierarhia de fișiere ~/uso.git
. Mergem în această ierarhie folosind cd ~/uso.git.
student@uso:~/uso.git$ grep -r "int main()" tema1/year/year.c:int main(){ lab03/ugly/ugly.c:}int main() tema4/headers/hello_5.c:int main() tema4/headers/hello_3.c:int main() tema4/headers/hello_7.c:int main() tema4/headers/hello_2.c:int main() tema4/headers/hello_1.c:int main() tema4/headers/hello_6.c:int main() tema4/headers/hello_4.c:int main() tema4/headers/hello_0.c:int main() lab02/anul_1/programare/simple_math.c:int main() lab02/anul_1/programare/hello.c:int main() lab02/anul_1/programare/teme/tema3/main.c:int main() lab02/anul_1/programare/teme/tema3/src/floats.c:int main() lab02/anul_1/programare/teme/tema3/src/constants.c:int main() lab02/anul_1/programare/teme/tema2/floats.c:int main() lab02/anul_1/programare/teme/tema2/constants.c:int main() lab02/anul_1/programare/teme/tema1/simple_math.c:int main() lab02/anul_1/programare/teme/tema1/hello.c:int main() lab02/anul_1/programare/teme/tema4/main.c:int main() lab02/anul_1/programare/teme/tema4/src/floats.c:int main() lab02/anul_1/programare/teme/tema4/src/constants.c:int main()
[1c] Căutați în interiorul fișierelor în ierarhia de fișiere ~/uso.git
patternul “include <stdio.h>“. Folosiți grep recursiv
.
În directorul ~/uso.git/labs/01-fs/support/need-to-know/3-compile
avem 2 fișiere: Makefile si hello_world.c. Rolul fișierului Makefile este de a compila sursa hello_word.c. Putem compila și executa fișierul obținut astfel:
student@uso:~/uso.git$ make gcc -o hello_world hello_world.c student@uso:~/uso.git$ ./hello_world Hello, World!
[3a] Intrați în directorul uso/labs/01-fs/support/need-to-know/
. Rulați executabilul din calea 3-compile
obtinut anterior din directorul curent. Hint: puteti vedea opțiunile utilitarului make folosint man make sau make –help la fel ca utilitarele folosite precedent.
[3b] Rămâneți în directorul uso/labs/01-fs/support/need-to-know/
. Copiați 3-compile/Makefile
in directorul curent, rulați Makefile și executați binarul obținut.
[3c] Creați un nou director numit nu_intrati
și în cadrul acestuia un fișier sursă manele_2018.c
în care să afișați un text la alegere. Copiați Makefile-ul folosit anterior și adaptați-l pentru cazul vostru. Compilați executabilul folosind Makefile și rulați executabilul.
Utilitarul df afișează informații despre sistemul de fișiere precum ocuparea acestuia. Folosirea acestuia:
student@uso:~/uso.git$ df --help Usage: df [OPTION]... [FILE]... Show information about the file system on which each FILE resides, or all file systems by default.
Cuvântul cheie df urmat de opțiuni și de numele fișierului. Fără numele fișierului, afișează informații despre întreg sistemul. Putem afla aceste opțiuni prin folosirea comenzii man df sau df –help la fel ca la utilitarele locate, mkdir și grep.
Redirectarea rezultatului se face prin operatorul >. Astfel:
student@uso:~/uso.git$ df -h > informatii_sistem student@uso:~/uso.git$ cat informatii_sistem Filesystem Size Used Avail Use% Mounted on udev 968M 0 968M 0% /dev tmpfs 200M 1,3M 199M 1% /run /dev/sda1 16G 6,1G 8,9G 41% / tmpfs 997M 0 997M 0% /dev/shm tmpfs 5,0M 4,0K 5,0M 1% /run/lock tmpfs 997M 0 997M 0% /sys/fs/cgroup /dev/loop0 87M 87M 0 100% /snap/core/5145 /dev/loop1 87M 87M 0 100% /snap/core/4917 /dev/loop2 13M 13M 0 100% /snap/gnome-characters/103 /dev/loop3 35M 35M 0 100% /snap/gtk-common-themes/319 /dev/loop7 15M 15M 0 100% /snap/gnome-logs/37 /dev/loop4 3,8M 3,8M 0 100% /snap/gnome-system-monitor/51 /dev/loop6 2,4M 2,4M 0 100% /snap/gnome-calculator/180 /dev/loop5 141M 141M 0 100% /snap/gnome-3-26-1604/70 tmpfs 200M 28K 200M 1% /run/user/1000
Bineînteles, am verificat că redirectarea a avut succes prin afișarea conținutului fișierului în care am redirectat.
[2d] Redirectați în fișierul ierarhiei.txt
rezultatul comenzii tree. Comanda trebuie executată din vârful ierarhiei.
[2e] Repetați redirectarea de mai sus în fișierul ierarhie_ascii, dar de data aceasta în format ASCII.
În directorul ~/uso.git/labs/01-fs/support/04-compile/
găsiți un set de fișiere și un fișier Makefile
pentru compilarea lor. Există o eroare ce ține de căi în sistemul de fișiere, astfel că nu merge compilarea în momentul rulării comenzii make
.
Corectați eroarea și obțineți fișierul executabil write_hello
.
Comenzile pe care le rulăm au la bază fișiere executabile în sistemul de fișiere. În momentul în care dăm o comandă, shell-ul caută într-o listă predefinită de directoare existența unui executabil cu ajutorul căruia să ruleze comanda respectivă. De exemplu, comanda ls
folosește executabilul /bin/ls
, astfel că rularea celor două comenzi de mai jos este echivalentă:
ls /bin/ls
Similar, comanda find
foloseșt executabilul /usr/bin/find
, comanda zip
folosește executabilul /usr/bin/zip
și așa mai departe.
Directoarele în care caută shell-ull executabilele aferente unei comenzi se găsesc într-o construcție de tip variabilă de mediu numită PATH
. Vom vorbi mai multe despre variabile și variabile de mediu la un laborator viitor. Pe moment, este suficient să știm că pentru a afișa valoarea variabilei PATH
folosim comanda
student@uso:~/uso.git/labs/01-fs$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Directoarele afișate, conținute de variabila PATH
sunt afișate în rezultatul comenzii, separate prin caracterul :
(două puncte, colon). Asta înseamnă ca dacă un utilizator tastează comanda ls
, shell-ul va căuta, în ordine, existența executabilului /usr/local/sbin/ls
, apoi /usr/local/bin/ls
, apoi /usr/sbin/ls
și așa mai departe. Când găsește un executabil îl va rula, ducând la afișarea rezultatului comenzii la terminal.
Calea către executabilul aferent unei comenzi poate fi afișată folosind comanda which
urmată de numele comnezii, ca mai jos:
student@uso:~/uso.git/labs/01-fs$ which ls /bin/ls student@uso:~/uso.git/labs/01-fs$ which find /usr/bin/find student@uso:~/uso.git/labs/01-fs$ which zip /usr/bin/zip
În rulările celor trei comenzi which
de mai sus am obținut calea către fișierele executabilele aferente respectiv comenzilor ls
, find
și zip
.
Putem verifica faptul că acele fișiere sunt executabile prin folosirea comenzii file
urmată de calea către fișierul executabil, cal mai jos:
student@uso:~/uso.git/labs/01-fs$ file /bin/ls /bin/ls: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=9567f9a28e66f4d7ec4baf31cfbf68d0410f0ae6, stripped student@uso:~/uso.git/labs/01-fs$ file /usr/bin/find /usr/bin/find: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=b920f53e0c67a31d8ef07b84b1344f87a0e82d71, stripped student@uso:~/uso.git/labs/01-fs$ file /usr/bin/zip /usr/bin/zip: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c828586e6e7cf929500a5b9c04faece9eceed5cc, stripped
În rezultatul rulării celor trei comenzi file
de mai sus vedem că apare informația ELF
, dynamically linked
. Fără a intra în detalii, acest lucru este indiciul că aceste fișiere sunt, într-adevăr fișiere executabile.
[6a] Găsiți fișierele executabilele aferente comenzilor useradd
, iotop
, tar
, gzip
. Verificați că cele patru fișiere indicate sunt fișiere executabile.
Bonus: De ce fișierele executabile pentru useradd
și iotop
se găsesc într-un director care conține sbin/
pe când tar
și gzip
se găsesc într-un director care conține bin/
(fără s
)? Folosiți Internetul și Google pentru aflarea răspunsului.
O situație frecventă în lucrul cu fișiere este să parcurgem toate fișierele dintr-o ierarhie. Eventual să facem apoi operații pe toate aceste fișiere: să schimbăm permisiuni, să afișăm informații, să ștergem unele fișiere. Pentru aceasta folosim utilitarul find
.
În mod implicit find
afișează recursiv toate intrările din directorul curent, așa cum se vede când rulăm comanda
student@uso:~/uso.git/labs/01-fs$ find . ./wiki ./wiki/basics.wiki ./wiki/concepts.wiki ./wiki/demo.wiki ./wiki/get-a-life.wiki ./wiki/nice-to-know.wiki ./wiki/recap.wiki ./wiki/need-to-know.wiki ./01-fs-g.zip ./support ./support/.gitignore ./support/get-a-life [...]
Dacă-i dăm un argument un director, va afișa recursiv toate intrările din acel director. De exemplu, comanda de mai jos afișează toate intrările din ierarhia /var/lib/apt/
:
student@uso:~/uso.git/labs/01-fs$ find /var/lib/apt /var/lib/apt /var/lib/apt/mirrors /var/lib/apt/mirrors/partial /var/lib/apt/daily_lock /var/lib/apt/lists [...]
[3a] Putem afișa folosind find
doar anumite tipuri de intrări, de exemplu doar fișiere. Pentru a afișa doar fișierele din directorul curent folosim opțiunea -type f
, la fel ca în comanda de mai jos:
student@uso:~/uso.git/labs/01-fs$ find -type f ./wiki/basics.wiki ./wiki/concepts.wiki ./wiki/demo.wiki ./wiki/get-a-life.wiki ./wiki/nice-to-know.wiki ./wiki/recap.wiki [...]
Observăm în output că sunt afișate numai fișiere, folosind opțiunea -type f
.
[3b] Putem afișa fișierele care corespund unui anumit pattern. De exemplu pentru a afișa toate fișierele cu extensia .tex
vom folosi opțiunea -name
, la fel în comanda de mai jos:
student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.tex' ./support/nice-to-know/fruits/pear.tex ./support/get-a-life/4-rename/5.tex ./support/get-a-life/4-rename/3.tex [...]
Observăm că sunt afișate numai fișierele cu extensia .tex
.
[3c] Putem folosi comanda find
pentru a aplica o altă comandă pe intrările găsite. De exemplu dacă dorim să ștergem toate fișierele cu extensia .c
vom folosi opțoiunea -exec
, la fel ca în comanda de mai jos:
student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.c' ./support/nice-to-know/fruits/apple.c ./support/get-a-life/2-passwd/reader.c student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.c' -exec rm {} \; student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.c' student@uso:~/uso.git/labs/01-fs$
Dacă la început aveam două fișiere cu extensia .c
(./support/nice-to-know/fruits/apple.c
și ./support/get-a-life/2-passwd/reader.c
) după rularea comenzii find acele fișiere dispar.
-exec rm {} \;
este mai complicată și nu o vom explica în detaliu aici. Pe scurt:
-exec
este opțiunea care dictează comenzii find
să execute comanda primită ca argumentrm
este comanda rulată pentru fiecare fișier găsit, adică acea comandă care șterge fișierul{}
este o construcție specifică opțiunii -exec
care înlocuiește numele fișierului; practic înseamnă că rulăm rm <nume-fisier>
pentru fiecare fișier descoperit\;
este un terminator de comandă, spunând că aici se încheie comanda transmisă argument opțiunii -exec
[3d] Pe baza celor de mai sus, ștergeți toate fișierele temporare din ierarhia curentă.
~
(tildă).
~/uso.git/labs/
. Folosiți comanda:
cd ~/uso.git/labs
De multe ori dorim să salvăm rezultatul afișat de o comandă (output) într-un fișier pentru a-l consulta ulterior. Acest lucru este util pentru comenzile care afișează multe informații pe care nu le putem vizualiza ușor sau pentru a reține snapshot-uri ale rulării unei comenzi pe care să le comparăm între ele. De exemplu, dacă rulăm comanda
ls > out.txt
Vom obține în fișierul out.txt
rezultatul rulării comenzii ls. Putem verifica acest lucru cu ajutorul comenzii
cat out.txt
Operatorul >
din shell este numit operator de redirectare, cu ajutorul căruia redirectăm rezutatul comenzii (adică ieșirea standard, standard output) în fișierul trimis ca argument.
Un caz de utilizare este atunci când dorim să rulăm o comandă fără a ne preocupa rezultatul rulării acesteia. În acest caz redirectăm ieșirea standard a comenzii la fișierul special /dev/null
. Fișierul special /dev/null
este un fișier de tipul “gaură neagră”: orice informație redirectată acolo se pierde.
Pentru a exemplifica redirectarea în fișierul special /dev/null
vom folosi utilitarul/comanda strace
. Comanda strace
monitorizează apelurile pe care le face o altă comandă către sistemul de operare (strace
– system call tracing). Pentru început rulăm comanda de mai jos și obținem rezultatul indicat:
student@uso:~/uso.git/labs$ strace ls execve("/bin/ls", ["ls"], 0x7ffdde615410 /* 35 vars */) = 0 brk(NULL) = 0x5651b5da3000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 [...] write(1, "00-intro 01-fs 02-process 03-"..., 10900-intro 01-fs 02-process 03-user 04-appdev 05-cli 06-hw-boot 07-storage 08-net 09-vm 10-sec 11-ctf [...]
Comanda strace
primește ca argument o altă comandă și argumentele aceleia. În cazul de mai sus, a primit ca argument comanda ls
. Apoi comanda strace afișează la ieșirea standard (standard output) rezultatul comenzii primite ca argument (la noi ls
) iar la ieșirea de eroare standard (standard error) rezultatul propriu (adică sumarul apelurilor pe care îl face comanda primită ca argument la sistemul de operare).
strace
. O folosim ca să demonstrăm aspecte ale redirectării și pentru că scenariile pe care le prezentăm sunt practice și utile.
[1a] Ne dorim să afișăm la terminal doar rezultatul comenzii strace
, adică apelurile realizate de comanda primită ca argument, fără să ne preocupe rezultatul comenzii. Pentru aceasta redirectăm ieșirea standard la /dev/null
, adică în acel fișier special gaură neagră. Rulăm acum fără redirectare și cu redirectare comenzile de mai jos pentru a investiga fișierele deschise de comanda ls
:
student@uso:~/uso.git/labs$ strace -e openat ls openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3 00-intro 01-fs 02-process 03-user 04-appdev 05-cli 06-hw-boot 07-storage 08-net 09-vm 10-sec 11-ctf strace.out +++ exited with 0 +++ student@uso:~/uso.git/labs$ strace -e openat ls > /dev/null openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3 +++ exited with 0 +++
În cazul redirectării ieșirii standard la fișierul special /dev/null
folosind operatorul >
, observăm că nu mai apare listarea de fișiere 00-intro …
reprezentând rezultatul comenzii ls
.
-e openat
al comenzii strace
ne permite să selectăm doar apelurile de deschidere de fișier pe care comanda primită ca argument (în cazul nostru ls
) le face la sistemul de operare.
[1b] Într-o situație ne interesează să redirectăm rezultatul comenzii strace
într-un fișier; adică acea înlănțuire de apeluri efectuate de comanda primită ca argument către sistemul de operare. Pentru aceasta, folosim operatorul 2>
de redirectare a ieșirii de eroare standard (standard error) ca mai jos:
student@uso:~/uso.git/labs$ strace -e openat ls 2> strace.out 00-intro 01-fs 02-process 03-user 04-appdev 05-cli 06-hw-boot 07-storage 08-net 09-vm 10-sec 11-ctf
În comanda de mai sus ieșirea de eroare standard (standard error) a fost redirectată în fișierul strace.out
; adică rezultatul comenzii strace
, adică șirul de apeluri ale comenzii ls
la sistemul de operare. La terminal a fost afișată ieșirea standard a comenzii, adică rezultatul comenzii ls.
Verificăm faptul că redirectarea a avut loc cu succes afișând conținutul fișierului strace.out
cu ajutorul comenzii
student@uso:~/uso.git/labs$ cat strace.out openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3 +++ exited with 0 +++
Observăm că, așa cum ne așteptam, rezultatul comenzii strace (lista de apeluri) a fost redirectată cu succes în fișier prin redirectarea ieșirii de eroare standard (standard error).
[1c] Ne poate interesa să redirectăm și rezultatul comenzii strace
într-un fișier și rezultatul comenzii primite ca argument. În acest caz folosim atât operatorul >
de redirectare a ieșirii standard (standard output) cât și operatorul 2>
de redirectare a ieșirii de eroare standard (standard error). Pentru aceasta folosim comanda:
student@uso:~/uso.git/labs$ strace -e openat ls 2> strace.out > ls.out
În comanda de mai sus am redirectat ieșirea standard (standard output), adică rezultatul comenzii ls
, în fișierul ls.out
și ieșirea de eroare standard (standard error), adică rezultatul comenzii strace
, în fișierul strace.out
. Putem verifica acest lucru prin afișarea conținutului celor două fișiere:
student@uso:~/uso.git/labs$ cat strace.out openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 openat(AT_FDCWD, "/usr/lib/locale/UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3 +++ exited with 0 +++ student@uso:~/uso.git/labs$ cat ls.out 00-intro 01-fs 02-process 03-user 04-appdev 05-cli 06-hw-boot 07-storage 08-net 09-vm 10-sec 11-ctf ls.out strace.out
Observăm că cele două fișiere obținute în urma redirectării (strace.out
și ls.out
) conțin rezultatele rulării comenzilor.
[1d] Construiți o comandă strace
care să nu afișeze nimic la terminal și să aibă în fișierul strace.out
apelurile de deschidere de fișiere realizate de comanda ps
.
ps
, adică să folosiți redirectarea către fișierul special /dev/null
.
[1e] Utilitarul grep
este folosit pentru a căuta un șir de caractere într-un fișier. De exemplu comanda de mai jos caută șirul root
în fișierul /etc/passwd
:
student@uso:~/uso.git/labs$ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash
După rularea unei comenzi putem folosi comanda echo $?
pentru a vedea dacă s-a rulat cu succes. De exemplu, dacă după rularea comenzii grep
de mai sus, rulăm comanda de verificare a unei rulări cu succes, obținem:
student@uso:~/uso.git/labs$ echo $? 0
Rezultatul 0
înseamnă o comandă anterioară s-a rulat cu succes.
Construiți o comanda grep
cu redirectare care să nu afișeze nimic la terminal (nici standard output, nici standard error). Iar după rularea acelei comenzi să verificați rularea cu succes. Pentru a verifica faptul că ați construit comanda grep
cum trebuie, folosind secvența de comenzi de mai jos:
student@uso:~/uso.git/labs$ grep 'a' /etc/passwd TODO student@uso:~/uso.git/labs$ echo $? 0 student@uso:~/uso.git/labs$ grep 'aaa' /etc/passwd TODO student@uso:~/uso.git/labs$ echo $? 1 student@uso:~/uso.git/labs$ grep 'aaa' /etc/pass TODO student@uso:~/uso.git/labs$ echo $? 2
În loc de TODO
trebuie să completați cu acele părți din construcție care folosesc redirectre pentru a nu afișa nimic la terminal.
O situație frecventă în lucrul cu fișiere este să parcurgem toate fișierele dintr-o ierarhie. Eventual să facem apoi operații pe toate aceste fișiere: să schimbăm permisiuni, să afișăm informații, să ștergem unele fișiere. Pentru aceasta folosim utilitarul find
.
În mod implicit find
afișează recursiv toate intrările din directorul curent, așa cum se vede când rulăm comanda
student@uso:~/uso.git/labs/01-fs$ find . ./wiki ./wiki/basics.wiki ./wiki/concepts.wiki ./wiki/demo.wiki ./wiki/get-a-life.wiki ./wiki/nice-to-know.wiki ./wiki/recap.wiki ./wiki/need-to-know.wiki ./01-fs-g.zip ./support ./support/.gitignore ./support/get-a-life [...]
Dacă-i dăm un argument un director, va afișa recursiv toate intrările din acel director. De exemplu, comanda de mai jos afișează toate intrările din ierarhia /var/lib/apt/
:
student@uso:~/uso.git/labs/01-fs$ find /var/lib/apt /var/lib/apt /var/lib/apt/mirrors /var/lib/apt/mirrors/partial /var/lib/apt/daily_lock /var/lib/apt/lists [...]
[3a] Putem afișa folosind find
doar anumite tipuri de intrări, de exemplu doar fișiere. Pentru a afișa doar fișierele din directorul curent folosim opțiunea -type f
, la fel ca în comanda de mai jos:
student@uso:~/uso.git/labs/01-fs$ find -type f ./wiki/basics.wiki ./wiki/concepts.wiki ./wiki/demo.wiki ./wiki/get-a-life.wiki ./wiki/nice-to-know.wiki ./wiki/recap.wiki [...]
Observăm în output că sunt afișate numai fișiere, folosind opțiunea -type f
.
[3b] Putem afișa fișierele care corespund unui anumit pattern. De exemplu pentru a afișa toate fișierele cu extensia .tex
vom folosi opțiunea -name
, la fel în comanda de mai jos:
student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.tex' ./support/nice-to-know/fruits/pear.tex ./support/get-a-life/4-rename/5.tex ./support/get-a-life/4-rename/3.tex [...]
Observăm că sunt afișate numai fișierele cu extensia .tex
.
[3c] Putem folosi comanda find
pentru a aplica o altă comandă pe intrările găsite. De exemplu dacă dorim să ștergem toate fișierele cu extensia .c
vom folosi opțiunea -exec
, la fel ca în comanda de mai jos:
student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.c' ./support/nice-to-know/fruits/apple.c ./support/get-a-life/2-passwd/reader.c student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.c' -exec rm {} \; student@uso:~/uso.git/labs/01-fs$ find -type f -name '*.c' student@uso:~/uso.git/labs/01-fs$
Dacă la început aveam două fișiere cu extensia .c
(./support/nice-to-know/fruits/apple.c
și ./support/get-a-life/2-passwd/reader.c
) după rularea comenzii find acele fișiere dispar.
-exec rm {} \;
este mai complicată și nu o vom explica în detaliu aici. Pe scurt:
-exec
este opțiunea care dictează comenzii find
să execute comanda primită ca argumentrm
este comanda rulată pentru fiecare fișier găsit, adică acea comandă care șterge fișierul{}
este o construcție specifică opțiunii -exec
care înlocuiește numele fișierului; practic înseamnă că rulăm rm <nume-fisier>
pentru fiecare fișier descoperit\;
este un terminator de comandă, spunând că aici se încheie comanda transmisă ca argument opțiunii -exec
[3d] Pe baza celor de mai sus, ștergeți toate fișierele temporare din ierarhia curentă.
~
(tildă).
În directorul ~/uso.git/labs/01-fs/support/04-compile/
găsiți un set de fișiere și un fișier Makefile
pentru compilarea lor. Există o eroare ce ține de căi în sistemul de fișiere, astfel că nu merge compilarea în momentul rulării comenzii make
.
Corectați eroarea și obțineți fișierul executabil write_hello
.