pdf - Środowisko programisty
Transkrypt
pdf - Środowisko programisty
Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 System plików Na poprzednich zajęciach wytłumaczyliśmy jak poruszać się po systemie plików. Warto jednak mieć świadomośc, że pliki są reprezentowane na dysku w trochę inny sposób. Podział na partycje Każdy dysk, na samym początku podzielony jest na partycje. Każda partycja to fragment wydzielonej przestrzeni dysku, który system operacyjny obsługuje niezależnie od pozostałych partycji. W ten sposób można na jednym fizycznym dysku zmieścić różne systemy plików i różne systemy operacyjne. Istnieją dwa podstawowe reprezentacje partycji: ∗ MBR (Master Boot Record) — wprowadzony w 1983. Informacja MBR zapisana jest zawsze w pierwszym dostępnym sektorze dysku. Obsługuje dyski do pojemności 2 TB operując 512-bajtowymi blokami, i standardowo pozwala na stworzenie maksymalnie czterech partycji. Nowsze wersje pozwalają na przekroczenie tych limitów, ale takie zabiegi nie są rozpoznawane przez wszystkie systemy operacyjne. ∗ GPT (GUID Partition Table) — wprowadzony z końcem XX wieku, obecnie obsługiwany przez wszystkie nowsze systemy operacyjne. Informacja GPT też zapisywana jest w pierwszych dostępnych sektorach dysku. Teoretyczna maksymalna pojemność dysku obsługiwana przez GPT to 9.4ZB (264 × 512) ale może być zwiększona poprzez zwiększenie wielkości bloku. GPT pozwala na stworzenie 128 partycji. System operacyjny Windows przypisuje kolejne litery do kolejnych partycji, poczynając od litery C. Każda pełna ścieżka zaczyna się od litery reprezentującą którąś z partycji. Pod linuxem nie ma takiego twardego związku. Partycja systemowa przypisana jest do katalogu głównego / ale pozostałe mogą być podpięte jako dowolny podkatalog, za pomocą komendy mount. Linux pozwala też mountowanie innych partycji, także wyjmowalnych lub połączonych przez sieć. Wpisując mount bez argumentów możemy zobaczyć wszystkie aktualnie podpięte partycje. $ mount | wc -l 44 Jak widać, w systemie TCS (na serwerze student) jest bardzo dużo różnych dysków podpiętych w ten sposób. I-węzły i bloki danych Każda partycja ma swój niezależny system plików. Współczesne systemy linuxowe operują w systemie ext2, ext3 lub ext4. Systemy te są do siebie podobne. Systemy przechowują Strona 1/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 dwa rodzaje informacji: ∗ Informacje o plikach przechowywane są w tablicy i-węzłów (ang. i-node table). ∗ Dane zawarte w plikach przechowywane są w blokach, gdziekolwiek w przestrzeni dyskowej. Każdy I-węzeł (ang. inode) reprezentuje dokładnie jeden plik. Przechowywane są tam wszystkie informacje o danych, ale nie sama zawartość pliku. ∗ ∗ ∗ ∗ ∗ ∗ Rodzaj pliku (zwykły plik, katalog, ...) Właściciel pliku Prawa dostępu Wielkość Czas modyfikacji Adresy bloków które przechowują dane I-węzeł nie przechowuje nazwy pliku! We wszystkich blokach do których odwołuje się dany i-węzeł znajduje się fragment zawartość pliku. Każdy blok ma z góry ustaloną większość. Na systemach TCS jest to 4KB. Do każdego bloku odwołuje się zawsze dokładnie jeden i-węzeł. Nie jest możliwe podzielenie bloku na mniejsze kawałki. W konsekewncji, jeśli wielkość pliku nie jest dokładną wielokrotnością wielkości bloku, trochę przestrzeni dyskowej zostaje zmarnowane. 719 723 . .. srodowisko 719 322 723 . .. plik1 . txt plik2 . txt 723 719 756 772 Katalog jest specjalnym rodzajem pliku. Iwęzeł odpowiadający za katalog ma taką samą strukturę jak każdego innego pliku. Zawartość katalogu zdefiniowana jest nie w węźle, a w bloku danych. To tam wypisane są nazwy zawieranych plików, i adres iwęzłów im odpowiadającym. Każdy katalog, nawet gdy jest on pusty, ma zawsze zdefiniowane dwie pozycje: ∗ . – wskazuje na swój własny i-węzeł. ∗ .. – wskazuje na i-węzeł odpowiadający za katalog nadrzędny. Podając parametr -i do komendy ls możemy podejrzeć informację o i-węzłach: Strona 2/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 $ ls - ali 723 drwxrwxr - x 2 pdan pdan 4096 Oct 719 drwx - - - - - x 10 pdan users 4096 Oct 756 -rw - rw -r - -+ 1 pdan pdan 52 Oct 772 -rw - rw -r - 1 pdan pdan 68 Oct 9 9 6 6 06:42 06:42 07:56 06:39 . .. plik1 . txt plik2 . txt Każda pozycja poprzedzona jest numerem i-węzła. Zwróćmy też uwage na liczbę występującą bezpośrednio po prawach dostępu. Na poprzednich zajęciach powiedzieliśy, że jest to “liczba połączeń”, ale nie wyjaśniliśmy czym te połączenia są. Liczba połączeń to liczba krawędzi przychodzących z któregokolwiek katalogu do danego i-węzła. W przypadku zwykłych plików, wartość ta zwykle wynosi 1, bo plik znajduje się w dokładnie jednym katalogu. Katalogi natomiast mają wiele przychodzących krawędzi z powodu plików . i .. Dowiązania Dowiązania (ang. link ) to cecha niektórych systemów plików (w tym tych omawianych przez nas) pozwalająca na tworzenie dodatkowych, niestandardowych połączeń w systemie plików. Dodatkowe połączenia pozwalają na szybszą nawigację w strukturze plików: dany plik można łatwo dowiązać do katalogu nas interesującego, mimo że tak na prawdę znajduje się on zupełnie gdzie indziej. Dowiązania można stosować zarówny do poszczególnych plików danych, jak i do całych katalogów. Jednym z takich zastosowań jest ukrywanie wersji programów. Często nazwa programu zawiera numer wersji. Na przykład na TCS/student zainstalowany jest kompilator języka C w kilku wersjach: ∗ gcc-4.9 – stara wersja 4.9.3 z 2015 roku ∗ gcc-5 – aktualna stabilna wersja 5.4.0 z czerwca 2016 roku ∗ gcc-6 – eksperymentalna wersja 6.0.0, być może zawierająca błędy Czasami, w szczególnych przypadkach użytkownik potrzebuje skompilować swój kod za pomocą konkretnej wersji kompilatora. Jednakże, w większości liczbie przypadków nie interesuje go jakie są wersje i potrzebuje po prostu najlepszej, stabilnej wersji która jest aktualnie dostępna. Dlatego w systemie dowiązany jest plik gcc który wskazuje na aktualną najlepszą wersję. $ cd / usr / bin $ ls - ali gcc * 128076 lrwxrwxrwx 128077 - rwxr - xr - x 9264709 - rwxr - xr - x 128079 - rwxr - xr - x ... 1 1 1 1 root root root root root 5 Jul 14 root 838008 Apr 14 root 915736 Aug 8 root 965264 Apr 15 17:36 04:23 17:22 23:44 gcc -> gcc -5 gcc -4.9 gcc -5 gcc -6 Możemy zauważyć, że plik gcc aktualnie wskazuje na gcc-5. W przyszłości, jak pojawi się nowsza stabilna wersja, będzie wskazywał w nowe miejsce. Niezależnie od wersji, Strona 3/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 użytkownik zawsze może wywołać gcc i mieć pewność że kompilator się uruchomi. Zwróćmy też uwagę na nowy atrybut pliku gcc: l – który oznacza, że jest to dowiązanie (link). Inne zastosowanie dowiązań: ∗ Inkrementatywne kopie zapasowe. ∗ Szybkie podmienianie plików, np. przy zmianie konfiguracji lub instalowaniu aktualizacji systemu ∗ Segregowanie tych samych zasobów według różnych kryteriów Istnieją dwa rodzaje dowiązań: ∗ Dowiązanie symboliczne (symbolic link, symlink ) operuje na nazwach plików. ∗ Dowiązanie twarde (hard link ) operuje na numerach i-więzów. Plik dowiązania symbolicznego przechowuje nazwę pliku docelowego. W przypadku gdy dowolna aplikacja próbuje otworzyć plik poprzez dowiązanie, system operacyjny automatycznie przeszuka drzewo katalogów by znaleźć właściwy plik docelowy. Na poziomie aplikacji, np. w Waszym kodzie C/C++ nie potrzeba dokonywać żadnych zmian by poprawnie obsłużyć takie dowiązania. Plik docelowy nie jest “świadom” istnienia dowiązań symbolicznych nań wskazujących. Jeśli plik docelowy zostanie usunięty bądź jego nazwa ulegnie zmianie, to nie będzie on osiągalny poprzez dowiązanie. Próba użycia takiego dowiązania zakończy się błędem. Dowiązania symboliczne tworzymy poleceniem: ln -s <plik docelowy> <nazwa dowiązania> 719 721 723 . .. plik1 . txt 719 322 721 dane . .. hard - link 723 719 721 Plik dowiązania twardego, to po prostu nowy wpis w katalogu używającego numer i-węzła, który już jest wykorzystywany przez inny plik. Twarde linki są nierozróżnialne od oryginału. Wszystkie wpisy prowadzące do danego i-węzła są równoważne. Twarde dowiązanie nie jest jednak pełna kopia pliku. Wszystkie pliki podpięte pod ten sam i-węzeł używają tą samą, jedną przestrzeń dyskową. Jest to ten sam plik, o wielu nazwach. Naturalnie, zmiana nazwy jednego z połączeń, łącznie z przeniesieniem pliku w inne miejsce, nie wpływa na pozostałe powiązania. Co więcej, próba usunięcia pliku poprzez jedno z połączeń nie wpłynie negatywnie na działanie pozostałych twardych dowiązań. Dzieje się tak ponieważ komenda rm wcale nie usuwa pliku, tylko usuwa wpis w katalogu. Strona 4/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 Jeśli po takiej operacji docelowy i-węzeł nie jest wskazywany przez żaden inny wpis, plik zostanie naprawdę usunięty. Ponieważ zwykłe pliki są zazwyczaj wskazywane tylko poprzez jedno połączenie, rm prowadzi do usunięcia takiego pliku. Jednakże, w kontekście twardych dowiązań, nie jest to już prawdą. Pozostałe połączenia pozostają bez zmian. Warto tu dodać, że gdy jakakolwiek aplikacja otwiera plik, tworzy ona podobne połączenie z plikiem. Gdy w trakcie działania aplikacji wszystkie połączenia do pliku zostaną usunięte, plik nadal pozostaje na dysku. Dopiero gdy aplikacja zamknię plik, zostaje on usunięty. Takie podejście jest szczególnie przydane na przykład podczas aktualizacji plików systemowych bez potrzeby restartowania komputera. Twarde dowiązania tworzy się poleceniem ln <plik docelowy> <nazwa dowiązania> — bardzo podobnie jak dowiązania symboliczne, ale bez parametru -s. Twarde dowiązania nie mogą być używane dla katalogów, gdyż może to złamać drzewiastą strukturę. Za pomocą takich dowiązań łatwo możnaby stworzyć cykle które mogłyby mieć katastrofalne skutki dla niektórych operacji rekurencyjnych (np. find). Twarde dowiązania nie mogą być też stosowane przy łączeniu plików z różnych partycji czy dysków sieciowych. Każda partycja dysponuje własną numeracją i-węzłów. Numeracja jest unikalna tylko w obrębie jednej partycji. W obu tych przypadkach można bez problemów używać dowiązań symbolicznych. Prawa dostępu Każdy i-węzeł przechowuje informację o właścicielu pliku i prawach dostępu. Prawa dostępu zdefiniowane są dla trzech kategorii ludzi: ∗ Właściciela pliku (u) ∗ Grupy przypisanej do pliku (g) ∗ Pozostałych użytkowników (o) Dla każdej kategorii można zdecydować, czy użytkownik może plik odczytac (r ), zapisać (w ) lub uruchomić (x ). Właściciel pliku może zmienić uprawnienia za pomocą komendy chmod. Składnia komendy to: chmod KOU < nazwa > gdzie ∗ K — znak lub kombinacja znaków definiujący kategorię użytkowników co do której dokonujemy zmianę (u, g, o). Można też użyć a dla wszystkich, równoważne z ugo. ∗ O — znak operacji: prawa dostępu można nadać + albo udebrać -. Strona 5/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 ∗ U — znak lub kombinacja znaków definiująca rodzaju uprawnień — r, w lub x. Przykłady nadawania praw: chmod u+x nazwa chmod ug+rx nazwa chmod a-rx nazwa daje użytkownikowi prawo do uruchamiania nadaje użytkownikowi i grupie prawo do czytania i uruchamiania zabiera prawo do czytania i uruchamiania dla wszystkich użytkowników Można również użyć systemu ósemkowego, aby ustawić prawa. Czytaniu (read) odpowiada 4, pisaniu (write) odpowiada 2, a wykonaniu (execute) 1. Każda cyfra odpowiada jednemu z kategorii użytkowników. Na przykład: chmod 755 helloshell.sh nadaje użytkownikowi prawa do pisania, czytania i uruchamiania (4+2+1), prawo czytania i uruchamiania (4+0+1) grupie i innym. Ponieważ prawa dostępu są zapisane w i-węźle, są one stałe, niezależnie przez które dowiązania plik jest otwierany. Dowiązanie symboliczne jest osobnym i-węzłem ze swoimi prawami, ale są one ignorowane – liczą się tylko i wyłącznie prawa dostępu zapisane w i-węźle docelowego pliku który otwieramy. Uprawnienia do katalogów nadaje się w dokładnie taki sam sposób co do zwykłych plików. Jak już wyjaśniliśmy wcześniej, z punktu widzenia systemu plików, katalog to po prostu specjalny rodzaj pliku. Jednakże, w konteście katalogów, warto wyjaśnić co dane uprawnienia oznaczają w praktyce: ∗ r – odczyt pozwala użytkownikowi odczytać nazwy w katalogu. ∗ w – zapis pozwala użytkownikowi stworzyć, zmienić lub usunąć pliki z danego katalogu. ∗ x – pozwala uzyskac dostęp do plików powiązanych z nazwami w danym katalogu. W szczególności, katalog z uprawnieniami r-- pozwoli nam zaledwie na wypisanie wszystkich nazw plików, bez podania jakiejkolwiek informacji czym właściwie są te pliki. Innymi słowy, mamy nazwy ale nie mamy dostępu do powiązanych z nimi i-węzłów. Natomiast katalog z uprawnieniami --x pozwoli nam otworzyć dowolny plik, ale nie powie nam jakie właściwie pliki tam są. SUID i SGID Istnieje jeszcze specjalna flaga SUID i SGID, włączana odpowienio przez u+s i g+s. Plik wykonywalny z taką flagą dziedziczy uprawnienia właściciela pliku gdy zostanie on uruchomiony. Programy z taką flagą pozwalają innym użytkownikom na wykonanie operacji której normalnie wykonać by nie mogli. Strona 6/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 Dla przykładu, program /bin/mount pozwala zamontowac nowy dysk czy zasób w określonym miejscu w systemie plików. Operacja taka wymaga uprawnien głównego administratora (tzw. roota). W normalnej sytuacji mount byłby dla mnie bezużyteczny, bardzo szybko bym się przekonał, że nie mam wystarczających uprawnień. Na szczęście mount ma ustawioną flagę SUID i root jest właścicielem pliku. Niezależnie kto uruchomi ten program, jego działanie będzie miało uprawnienia roota, i niezbędne zmiany będą mogły być dokonane. Naturalnie, trzeba być bardzo ostrożnym nadając flagi SUID lub SGID szczególnie gdy jest się administratorem. Jeśli program z taką flagą zawiera błąd, złośliwy użytkownik może próbować uzyskać szerszy dostęp do komputera niż oryginalnie założono. Drzewo katalogów w systemie Linux Niezależne od wersji systemu Linux, katalog główny i niektóre podkatalogi wyglądają bardzo podobnie. / /bin /boot /dev /etc /home /initrd /lib /media /opt /proc /root /tmp /usr katalog główny. Tu wszystko się znajduje. podstawowe programy systemu i powłoki. Część z komend które przedstawiliśmy na poprzednich zajęciach to są tak na prawdę osobne programy, które znajdują się właśnie tutaj. pliki startowe i jądro linuxa urządzenia peryferyjne komputera, reprezentowane jako specjalne pliki, oznaczane literą c. Pliki te nie rezydują na żadnym z dysków, ale wykorzystują te same funkcje zapisu i odczytu, pozwalając różnym aplikacjom z łatwością komunikować się z tymi urządzeniami. pliki konfiguracyjne prywatne pliki użytkowników zawiera informacje potrzebne do startu systemu. Na TCSie widnieje jako symlink do jednego z plików w /boot. zawiera biblioteki dynamiczne potrzebne do uruchamiania różnych programów. Wasze programy w C też z tych plików korzystają. tu domyślnie mountowane są dyski zewnętrzne (CD-ROMy, dyskietki, pendrive-y) dodatkowe programy niezależnych dystrybutorów, nie związanych z daną wersją Linuxa. Na TCS-ie znajdziecie tutaj na przykład satori wirtualny system plików reprezentujące aktualne zasoby systemu. Tu można odczytać np. parametry procesora (/proc/cpuinfo) czy pamięci (/proc/meminfo). katalog domowy głównego administratora systemu. pliki czasowe. Mogą ulec usunięciu np. przy restarcie systemu. programy i biblioteki dla programów użytkownika. Dla programisty to bardzo ważny katalog! Strona 7/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 /usr/bin narzędzia programistyczne. Tu znajdziecie m. in. kompilatory C i C++ /usr/games bo każdy programista musi się czasem rozerwać :) /usr/include pliki nagłówków do C i C++, zarówno te standardowe jak i dodatkowych pakietów zainstalowanych na Linuxie /usr/lib pliki bibliotek /usr/local podobny do /usr. Ideowo tu znajdują się pliki bardziej lokalne dla danej maszyny, ale rozróżnienie to jest często niejasne w praktyce. /usr/share domyślne pliki konfiguracyjne, rysunki, dokumentacje zainstalowanych bibliotek, itp. /usr/src pliki źródłowe /var Tu pojawiają się m.in. niektóre logi, cache plików internetowych, zadania dla drukarek, itp. Wszystkie te pliki mają cechę, że ich zawartość i liczba często zmienia się w czasie w wyniku normalnego działania systemu. Drzewo typowego projektu w C/C++ Każdy programista w ciągu kariery spotyka się z większymi projektami, które składają się z wielu plików. Mały program w C lub C++ zawiera się w pojedyńczym pliku. Taki program program.c kompilujemy za pomocą gcc program.c -o program – i gotowe! Jednakże, większe projekty często podzielone są na większą liczbę plików. Zarządzanie i kompilacja takich projektów jest bardziej skomplikowana. Podstawowy proces kompilacji składa się z dwóch etapów: ∗ Każdy plik źródłowy .c lub .cpp jest kompilowany do pliku obiektowego .o. Zawiera on kod maszynowy pojedyńczych funkcji oraz spis wszystkich funkcji które dany plik zawiera (i je eksportuje) lub potrzebuje (importuje). Kod maszynowy zawiera luki: adresy funkcji importowanych nie są znane. ∗ Wszystkie pliki obiektowe, wraz ze statycznymi bibliotekami, musza zostać połączone. Jest to zadanie linkera, który łączy wszystkie funkcje w jeden plik programu. Adresy wyeksportowane przez jeden plik są używane do uzupełnienia adresów funkcji importowanych w innych plikach. Pojedyńcze pliki kompilujemy za pomocą: gcc plik . c -c -o plik . o ∗ <nazwa> – argument pozycyjny to nazwa pliku który kompilujemy. ∗ -c – oznacza, że wykonujemy samą kompilację bez linkowania. ∗ -o <nazwa> – precyzuje jak ma się nazywać plik który generujemy. Domyślnie jest to nazwa pliku kompilowanego, z zastąpionym .c przez .o. Strona 8/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 Jak już skompilujemy każdy plik z osobna, połączyć je można za pomocą linkera o nazwa ld. Łatwiej jest jednak ponownie wywołać gcc z plikami .o jako argumentami. Program gcc wywoła tego samego linkera, ale uzupełni argumenty o domyślne wartości dla języka C. gcc plik1 . o plik2 . o -o program ∗ <nazwa> – argument pozycyjny to nazwa pliku który chcemy łączyć. Należy tu wypisać wszystkie pliki obiektowe które uprzegnio wygenerowaliśmy. ∗ -o <nazwa> – precyzuje jak ma się nazywać plik programu który generujemy. Domyślnie jest to zawsze a.out. Kompilując język C++ wystarczy zamienić gcc przez g++ w powyższych komendach. Oba kompilatory przyjmują te same parametry i flagi. Zauważmy, że projekt się rozrasta: dla każdego pliku źródłowego, generujemy nowy plik pośredni .o. Jest to plik tworzony podczas kompilacji, ale gdy otrzymamy główny program – taki plik nie jest już potrzebny. Z czasem może okazać się, że musimy też zawrzeć w projekcie dokumentację, lub kod źródłowy bibliotek zewnętrznych napisanych przez kogoś innego. Bardziej skomplikowane projekty moga też tworzyć jeszcze więcej różnych plików pośrednich. Dlatego każdy projekt, nawet jeśli zawiera on tylko dwa pliki źródłowe, warto podzielić na podkatalogi. Typowy podział to: projekt projekt/bin projekt/build projekt/contrib projekt/data projekt/doc projekt/include projekt/src projekt/test katalog główny. Bezpośrednio w tym katalogu umieszcza się niewiele plików. Głównie jest tam skrypt kompilujący/instalujący, krótki opis działania programu oraz informacja o prawach autorskich i licencji. Tu generowane są końcowe pliki binarne, takie jak programy. Katalog na wszystkie pliki pośrednie dla procesu kompilacji. Narzędzia innych osób na których dany projekt się opiera. Dane na których program operuje Dokumentacja, opis programu, notatki Jeśli projekt jest biblioteką – tu umieszane są pliki nagłówków (header file). Takie pliki zawierają deklaracje bez definicji. Tu umieszczony jest kod źródłowy. Tu jest kod testujący program, lub jego fragmenty. Powyższa lista nie jest wyczerpująca. W danym projekcie może pojawić się więcej katalogów w zależności od potrzeb. Te są najpopularniejsze. Strona 9/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 Cytowanie w systemach UNIXowych Cytowanie (ang. quoting) ma na celu usuwanie interpretacji znaków specjalnych przez powłokę. Najprostszym sposobem usunięcia interpretacji jest użycie znaku maskującego: \. W nastęþującym przykładzie shell nie interpretuje znaków końca linii. $ echo This could be \ a very \ long line\! This could be a very long line! Poza tym mamy trzy rodzaje cudzysłowów: ’’, "" oraz ‘‘. Pojedyncze cudzysłowy, te wymienione jako pierwsze maskują znaczenie wszystkich znaków specjalnych. Podwójne cudzysłowy pozwalają na interpretacje niektórych cudzysłowów. Natomiast nie interpretują innych takich, jak * albo ?. Ostatni rodzaj cudzysłowów pozwala na umieszczenie w tekście wyniku działania pewnych komand. Dla przykładu warto porównać dwie następujące komendy. $ echo ’W tym katalogu teraz przebywasz: ‘pwd‘’ W tym katalogu teraz przebywasz: ‘pwd‘ $echo "W tym katalogu teraz przebywasz: ‘pwd‘" W tym katalogu teraz przebywasz: /home/wrona. xargs -name "*.c" find xargs rm -f Polecenie xargs służy do konstruowania listy argumentów ze standardowego wejścia dla innych poleceń i wykonywania tychże poleceń. Brzmi to dość abstrakcyjnie i może enigmatycznie ale kilka zastosowań polecenia xargs jest uważanych za jedne z najbardziej użytecznych sekwencji komend w Linuksie. Przykład. Skasuj wszystkie pliki z rozszerzeniem .c w bieżącym katalogu. Oczywiście możemy zrobić to tak: rm rm *.c Możemy, też tak: find . -name "*.c" | xargs rm Strona 10/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 To jednak nie zadziała gdy mamy pliki z białymi znakami w nazwie. Możemy to poprawić tak, aby nie było komunikatu błędu: find . -name ’*.c’ | xargs rm -f Ale plik z białymi znakami w nazwie dalej pozostanie nieskasowany. Poprawnie zadziała dopiero, gdy zmienimy terminatora nazwy plików na znak null. Do tego potrzebujemu flagi -print0 w find oraz -0 w xargs. find . -name ’*.c’ -print0 | xargs -0 rm Wprawdzie polecenie find -exec rm pozwala nam usuwać znalezione pliki, to następuje to wolniej niż skorzystanie z xargs. Jest tak, ponieważ find uruchamia dla każdego pliku pojedynczo plecenie rm. Natomiast xargs przekazuje tyle argumentów ile polecenie maksymalnie może przyjąć. W przypadku rm jest to na tyle duża liczba, że znacząco zwiększa wydajność usuwania plików. Przykład. Dla każdego pliku w bieżącym katalogu o rozszerzeniu .txt wydrukuj jedną linię na standardowe wyjście zawierającą liczbę linii w tym pliku i jego nazwę. ls -1 *.txt | xargs -n 1 wc -l Flaga -n 1 w xargs, powyżej, pozwala na przekazanie tylko jednego argumentu na raz do xargs. Przykład. Przesuń wszystkie pliki o rozszerzeniu .bak do katalogu ~/old.files. find . -name "*.bak" -print0 | xargs -0 -I {} mv {} ~/old.files find . -name "*.bak" -print0 | xargs -0 -I file mv file ~/old.files Zwróć uwagę na opcję -I. Po niej podawany jest znacznik, który ma być interpretowany w poleceniu jako miejsce gdzie xargs ma wkleić dane otrzymane na standardowym wejściu. Domyślnie xargs wstawia te dane na końcu tworzonego polecenia (patrz poprzednie przykłady). Jednak polecenie mv wymaga aby najpierw była nazwa pliku (bądź plików) które mają być przeniesione, a na końcu ma być miejsce przeniesienia. Powyższe dwie linie różnią się jedynie ciągiem znaków podanym jako wspomniany znacznik. Przykład. W każdej linii pliku „test.in” znajduje się jedno słowo. Utwórz pliki o nazwach takich jak słowa z „test.in” Niestety polecenie touch nie wczytuje danych ze standardowego wejścia, a jedynie jako argumenty. Więc jedynym sposobem jest użycie xargs: cat test.in | xargs touch Tak jak wcześniej omawialiśmy powyższa sekwencja nie zadziała dla nazw z białymi znakami. Przykład. cat plik | xargs -n 1 -I {} sh -c "mkdir {}; touch {}/{}" Strona 11/12 Środowisko programisty Zestaw 3 Semestr zimowy 2016/2017 Kraków, 18-20 października 2016 Dla każdego słowa w pliku plik tworzy katalog o tej nazwie i pusty plik w tym katalogu o tej samej nazwie. Zwróć uwagę, iż xargs wywołuje tutaj nową instancje powłoki poleceń (poprzez polecenie sh). Dzięki temu możemy wykonać więcej niż jedno polecenie używając argumentów przekazanych przez xargs. Przydatne opcje find (i) find . -name ’*.c’ -maxdepth 1 — drukuje nazwy plików i katalogów o nazwie zakończonej .c w aktualnym katalogu ale nie w jego podkatalogach, (ii) find . -name ’*.c’ -type f — drukuje nazwy plików o nazwie zakończonej .c w aktualnym katalogu i podkatalogach, (iii) find . -name ’*.c’ - type f -size 0 — drukuje nazwy pustych plików w aktualnym katalogu i podkatalogach Strona 12/12