Tags Posts tagged with "bash"

bash

przez -
1 4632
Sieć

W Internecie dostępnych jest wiele serwisów, które testują prędkość naszego łącza. Jedne pokazuję wyniki w formie obrazków, sygnatur, posiadają ciekawą formę graficzną, kuszą wyglądem. Na wyniki takich testerów trzeba patrzeć z przymrużeniem oka. W tym artykule postaramy się napisać prosty tester prędkości łącza. Będzie on testował jak szybko jesteśmy w stanie pobierać plik z Internetu. Również i nasz skrypt nie będzie doskonały.

Przecież nam chodzi o poznanie Basha, a nie pisanie idealnej aplikacji do testowania prędkości łącz internetowych. W skrypcie wykorzystamy bardzo potężne i proste narzędzie jakim jest GNU Wget.

GNU Wget pozwala na pobieranie plików przy wykorzystaniu takich protokołów jak HTTP, HTTPS oraz FTP najpowszechniej używanych protokołów internetowych. Jego cechą wyróżniającą jest stosunek możliwości do niewielkich rozmiarów. Wget zaliczany jest do kategorii narzędziowych programów sieciowych i rozpowszechniany jest na licencji typu Open Source.

Wget może przedstawić się jako przeglądarka (opcja -U, np. wget -U "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021003"). Przykładowe użycie wgeta obrazuje poniższy log:

paszczak000@hell:~/skrypty/bash$ wget http://temp.thecamels.org/test.img
--09:01:38--  http://temp.thecamels.org/test.img
           => `test.img'
Translacja temp.thecamels.org... 78.47.147.217
Łączenie się z temp.thecamels.org|78.47.147.217|:80... połączono.
Żądanie HTTP wysłano, oczekiwanie na odpowiedź... 200 OK
Długość: 10,485,760 (10M) [application/x-img]

100%[=================================================================================================================================================>] 10,485,760     1.81M/s    ETA 00:00

09:01:44 (1.77 MB/s) - `test.img' saved [10485760/10485760]

Proces pobierania można wygodnie obserwować na ekranie dzięki wypisywanym znakom ===>, z których każdy znak = reprezentuje ustaloną ilość otrzymanych danych (domyślnie 1KB).

Jeżeli już znamy program, który będzie pobierał pliki z Internetu – czas na wykorzystanie jego możliwości. Wykorzystamy do tego polecenia wget, awk. Pierwsze z nich zajmie się pobieraniem pliku z ustalonego przez nas serwera, a drugie będzie odpowiedzialne za wyświetlenie wyników na ekranie. Dla zwiększenia wiarygodności wyników, zrobimy prostą pętlę, która powtórzy test kilka razy. Skrypt wygląda następująco:

if [ "$1" != "" ];
then
        stop=$1
        for (( i=1; i<=stop; i++ )); do
                wget -O /dev/null http://temp.thecamels.org/test.img 2>&1 | awk '/saved/ { gsub(/.*\(|\).*/, ""); print; }';
        done
else
        echo "Podaj ilosc prob np: ./speed_tester.sh 10";
fi

Zaczniemy od pobrania jakiegoś pliku testowego. Następnie uruchamiamy polecenie wget z parametrem -O. Parametr ten skieruje nam pobrany plik do czarnej dziury (/dev/null). Dzięki temu nie będziemy śmiecić sobie systemu jakimiś plikami. Następnie skorzystamy ze standardowych strumieni. Za pomocą symbolu 2>&1 przekierowujemy standardowy strumień błędów (STDERR) do standardowego wyjścia (STDOUT). Wynikiem działania skryptu będzie:

./speed_tester.sh 10
1.74 MB/s
1.73 MB/s
1.48 MB/s
1.73 MB/s
1.75 MB/s
1.50 MB/s
1.74 MB/s
1.73 MB/s
1.75 MB/s
1.73 MB/s

Następnie za pomocą awk wycinamy interesującą nas wartość, czyli prędkość pobierania pliku. Wynik ten drukujemy na ekranie i kończymy wykonywać skrypt. Modyfikując powyższy skrypt możemy napisać sobie proste narzędzie, które będzie nam monitorowało strony Internetowe, którego wynikiem będzie takie oto zestawienie:

Web page	Date	WWW	Size	Transfer
TheCamels	08:43	OK	8	3.57 MB/s
Empik		08:43	OK	36	278.96 KB/s
Orange		08:43	OK	20	842.21 KB/s
ICS		08:43	ERROR	0	0.00 KB/s
WP		08:43	OK	8	306.01 KB/s
Onet		08:43	OK	20	935.31 KB/s

I to by było na tyle. Oczywiście do wyników zwracanych przez skrypt należy podchodzić z przymrużeniem oka. Prędkość ta zależy przecież od wielu czynników jak np. możliwości serwera, z którego pobieramy plik, priorytety itp.

przez -
4 11922
Klawiatura, sprzęt

Czasem zdarza się, że mamy ogromną ilość plików zapisanych WIELKIMI literami, a z jakiegoś powodu chcemy zamienić je na małe. Jeżeli tych plików jest kilka, możemy zmienić ich nazwy ręcznie. Ale co będzie jeśli musimy zmienić ponad 1000 plików, które są zdjęciami z wakacji? Z pomocą przyjdzie nam polecenie tr. Jest to narzędzie, za pomocą którego można zmieniać i usuwać znaki. Polecenie to czyta ze standardowego wejścia i wynik wypisuje na standardowe wyjście.

Zaczynając przygodę z poleceniem tr poznajmy jego podstawowe funkcje. Wydając polecenie: tr abc xyz zamienimy każdy nak występujący na i-tym miejscu w abc jest zastępowany znakiem występującym na i-tym miejscu w xyz. Zatem każde a na wejściu zamieni się na x, b na y i c na z. Zatem sprawdźmy, czy to prawda:

paszczak000@hell:~$ echo Ala ma kota i lubi go całować | tr abc xyz
Alx mx kotx i luyi go zxłowxć

Jak widać polecenie tr poprawnie zamieniło znaki. Ale to nie wszystko. Możemy wykorzystać tr do usuwania znaków podanych na wejściu. Do tego służy parametr -d. Wydając polecenie tr -d abc skasujemy wszystkie znaki abc jakie znajdą się na wejściu. Jeśli dodamy parametr -c, spowodujemy, że usuniemy wszystkie znaki, które nie podaliśmy w parametrze. Przykład:

paszczak000@hell:~$ echo Ala ma kota i lubi go całować | tr -d a
Al m kot i lubi go cłowć

paszczak000@hell:~$ echo Mam na imie Piotrek. Mój numer to telefonu to 948-234-446-32 | tr -cd 0123456789
94823444632

Jak widać w pierwszym przykładzie usunęliśmy wszystkie literki a. Natomiast w drugim chcieliśmy wyciągnąć sam numer telefonu z ciągu znaków. tr usunął wszystkie znaki poza cyframi (0123456789).

Znając podstawowe funkcje polecenia, możemy przystąpić do próby zmiany wielkich liter na małe. W Internecie dostępne jest wiele tego typu przykładów, dlatego przyjrzymy im się z bliska. Najprostszą metodą jest wykorzystanie skryptu:

for file in * ; do
	mv "$file" `echo "$file" | tr '[A-Z]' '[a-z]'`
done

Pętla for pobierze nam wszystkie pliki w danym katalogu, po czym poleceniem mv oraz tr zmienimy im nazwę. W nawiasach kwadratowych podany jest zakres znaków jakie mają zostać zamienione. Możemy delikatnie zmodyfikować skrypt i wykorzystać klasy znaków dla polecenia tr:

for file in *
do
	mv $file `echo $file | tr [:upper:] [:lower:]`
done

W tym wypadku wykorzystując klasy upper i lower Wykorzystując klasy możemy określić jakie zakresy znaków mają być brane pod uwagę. Mamy do dyspozycji:

  • alnum – znaki alfanumeryczne
  • alpha – litery
  • cntrl – znaki kontrolne
  • digit – cyfry
  • graph – znaki graficzne, bez spacji
  • lower – małe litery
  • print – znaki pisarskie w tym spacja
  • punct – znaki interpunkcyjne
  • space – spacje, białe znaki
  • upper – wielkie litery
  • xdigit – znaki hexadecymalne

Taką samą operację (zmiana wielkich liter na małe) możemy wykonać z wykorzystaniem Perla w skrypcie:

for file in `ls -1|perl -ne 'print "$_" if (/[A-Z]/);'`
do
	mv ${file} `echo ${file}|perl -ne 'chomp;print "$_" if (tr/A-Z/a-z/);'`;
done

W Internecie dostępne są również inne modyfikacje powyższych skryptów. Jedną z nich jest kod napisany przez Johna Dubois, a następnie zmodyfikowany przez Chet Ramey:

#!/bin/bash
#
#  Changes every filename in working directory to all lowercase.
#
#  Inspired by a script of John Dubois,
#+ which was translated into Bash by Chet Ramey,
#+ and considerably simplified by the author of the ABS Guide.

for filename in *                # Traverse all files in directory.
do
fname=`basename $filename`
n=`echo $fname | tr A-Z a-z`  # Change name to lowercase.
if [ "$fname" != "$n" ]       # Rename only files not already lowercase.
then
mv $fname $n
fi
done

exit $?

Niestety skrypt ten nie poradzi sobie z plikami, które zawierają różnego rodzaju białe znaki oraz znak nowej linii. Stephane Chazelas zaproponował następujące rozwiązanie:

# The above script will not work on filenames containing blanks or newlines.
# Stephane Chazelas therefore suggests the following alternative:

for filename in *    # Not necessary to use basename,
# since "*" wont return any file containing "/".
do n=`echo "$filename/" | tr '[:upper:]' '[:lower:]'`
#                             POSIX char set notation.
#                    Slash added so that trailing newlines are not
#                    removed by command substitution.
# Variable substitution:
n=${n%/}          # Removes trailing slash, added above, from filename.
[[ $filename == $n ]] || mv "$filename" "$n"
# Checks if filename already lowercase.
done

exit $?

Polecenie tr jest bardzo przydatne jeśli chcemy usunąć z nazw naszych plików zbędne znaki lub ustandaryzować ich wielkość. Więcej informacji na temat tr, dostępne jest w manualu.

przez -
5 16442
Konsola

Przeglądanie logów systemowych, z serwerów jest zajęciem monotonnym i żmudnym, zwłaszcza kiedy musimy obejrzeć miliony białych linii na czarnym ekranie. W takich sytuacjach trudno jest wyłapać interesujące nas wartości, a w szczególności błędy. Dobrym pomysłem byłoby napisanie prostego skryptu, który w jakiś sposób wyszczególni interesujące nas wartości.

Kolory w Bashu

Korzystanie z kolorów jest dość proste. Pierwszym krokiem jest stworzenie tekstu bez użycia dodatkowych kolorów. Kolejnym krokiem jest dodanie specjalnej sekwencji sterującej terminalem (nie powłoką bash), która doda nieco barw do naszego tekstu. Standardowy terminal systemowy oraz te graficzne umożliwiają zmianę koloru tła, pierwszego planu (tekst), a także wagi czcionki (czy tekst jest pogrubiony, czy nie). Do wyboru mamy osiem podstawowych kolorów.

Użycie danego koloru wiąże się z zastosowaniem specjalnej sekwencji sterującej umieszczając odpowiednie liczby pomiędzy \e[ (znak ucieczki) i m. Jeśli chcemy użyć większą ilość kodów, używamy znaku średnika pomiędzy każdą z nich. Najprostszym „kolorem” jest powrót do wartości domyślnych: "\e[0m".

Zastosowanie powyższego kodu spowoduje powrót do wartości domyślnych ustawień terminala, dotyczących koloru pierwszego planu, tła oraz wagi tekstu. Najczęściej wykorzystywać będziemy go do zakańczania kolorowania tekstu. Aby odkryć kolory jaki umożliwia nam terminal wystarczy uruchomić prosty skrypt:

#!/bin/bash
esc="\033["
echo -n " _ _ _ _ _40 _ _ _ 41_ _ _ _42 _ _ _ 43" 
echo "_ _ _ 44_ _ _ _45 _ _ _ 46_ _ _ _47 _"
for fore in 30 31 32 33 34 35 36 37; do
	line1="$fore  "
	line2="    "
	for back in 40 41 42 43 44 45 46 47; do
		line1="${line1}${esc}${back};${fore}m Normal  ${esc}0m"
		line2="${line2}${esc}${back};${fore};1m Bold    ${esc}0m"
	done
	echo -e "$line1\n$line2"
done

W terminalu powinniśmy zobaczyć następującą paletę kolorów:

Konsola z tablicą kolorów

Teraz, aby otrzymać kod koloru najpierw należy wybrać odpowiedni kolor z tablicy. Następnie należy znaleźć liczby odpowiadające pierwszemu planowi (30-37) i tłu (40-47). Przykładowo, jeśli chcemy użyć zielonego koloru na czarnym tle, musimy użyć liczb 32 i 40 (echo -e "\033[32;40m"). Wiedząc w jaki sposób możemy kolorować tekst w konsoli możemy napisać proste skrypty kolorujące logi systemowe.

Loco oraz CCZE

Oczywiście nic nie stoi na przeszkodzie, aby wykorzystać już istniejące aplikacje do kolorowania logów. Pierwszą z nich jest program napisany w języku C o nazwie CCZE. Program jest modularny dzięki czemu za pomocą odpowiednich pluginów może kolorować logi z takich aplikacji lub usług jak:

  • apm
  • exim
  • fetchmail
  • httpd
  • postfix
  • procmail
  • squid
  • syslog
  • ulogd
  • vsftpd
  • xferlog
  • i wiele, wiele więcej

Uruchomienie kolorowania logów za pomocą tej aplikacji jest bardzo proste. Wystarczy na końcu polecenia, którym przeglądamy logi opisać | ccze.

tail -100f /var/log/auth.log | ccze

Taki efekt powinniśmy uzyskać:

CCZE kolorujące auth.log

Możemy również skorzystać ze skryptu napisanego w języku Perl, którego autorem jest Jules Stuifbergen. Chodzi tutaj o skrypt loco. Wykorzystuje on moduł Perla zwany Term::ANSIColor do kolorowania tekstu. Również tutaj uruchomienie skryptu jest bardzo proste:

tail -100f /var/log/auth.log | perl loco

Taki efekt powinniśmy uzyskać:

loco kolorujące auth.log

Tego typu rozwiązań w Internecie znajdziemy jeszcze dość dużo. Tak czy siak, najlepiej jest napisać własne kolorujące skrypty, które pomogą nam w przeglądaniu logów.

przez -
10 5792
Konsola program

Fork – bomba (ang. fork bomb) jest swego rodzaju atakiem Denial of Service. Metoda ta opiera się na szybkim stworzeniu wielu kopii programu, które unieruchomią system. Ponieważ w wieloprocesowym tylko określona ilość procesów może być efektywnie wykonywana naraz, stworzenie odpowiednio dużej liczby procesów może unieruchomić system. Wykorzystując funkcję fork(), która służy do tworzenia nowych procesów, możemy zapełnić tablicę procesów systemu operacyjnego.

Tworząc odpowiedni program, polecenie możemy w nieskończoność tworzyć nowe procesy. Unieruchomienie takiej reakcji łańcuchowej jest praktycznie niemożliwe. W takiej sytuacji wywołanie nowego procesu (mającego na celu np. zabicie procesów bomby) jest wstrzymane do czasu zwolnienia choćby jednego wpisu, co jednak jest mało prawdopodobne, ponieważ każdy proces bomby jest gotów w tym momencie się rozmnożyć.

GranicaKażdy z nowo utworzonych procesów wykonuje jakiś kod – działa w tle. Planista systemowy każdemu przydziela czas procesora. Ponieważ procesy tworzą nam się w nieskończoność, czas jaki im jest przydzielany dąży do 0. Takie działanie praktycznie unieruchamia system.

Przejdźmy teraz do samego kodu, który wywoła taką bombę w naszym systemie. Wystarczy wdać w konsoli proste polecenie.

:(){ :|:& };:

Nie polecam uruchamiać go na maszynie, która nie ma ustawionych limitów. W ten sposób po prostu zawiesimy system.

Żeby zrozumieć działanie tego polecenia, zapiszmy je w troszkę wygodniejszej formie:

:(){
  :|:&
};:

Na samym początku tworzona funkcja o nazwie :, która nie przyjmuje żadnych argumentów. W swoim ciele, które jest ograniczone znakami { } wywołuje się rekurencyjnie dwukrotnie, oraz przekazuje strumieniem swoje wyjście do innej instancji tej funkcji. Ten strumień to mechanizm nienazwanych potoków (pipes, |). Następnie przechodzi do tła &, dzięki czemu zabicie procesu – ojca nie zabije procesów – potomków. Średnik kończy definicję funkcji, a końcowy dwukropek jest jej pierwszym wywołaniem.

A tutaj bardziej przejrzysty zapis tej funkcji:

bomb() {
 bomb | bomb &
}; bomb

Kiedy uruchomimy na komputerze taką bombę, praktycznie staje się niemożliwe aby odzyskać kontrolę nad systemem bez jego ponownego uruchomienia. Tak naprawdę jedynym sposobem na zniszczenie takiej bomby jest zabicie wszystkich jej procesów. Niestety próba użycia programu do zabijania procesów kill, potrzebuje utworzenia odrębnego procesu, co może okazać się niemożliwe ze względu na brak wolnej pamięci lub gdy nie ma wolnych miejsc w tablicy procesów.

Jedyną skuteczną metodą obrony przed fork – bombami jest ustalenie górnego limitu procesów, jakie może utworzyć dany proces, lub użytkownik (dotyczy to również jego dalszych potomków). W momencie kiedy proces będzie próbował utworzyć inny proces, a jego rodzic posiada już więcej niż przewiduje maksimum, sklonowanie nie zachodzi. Na konsoli powinien wtedy pojawić się następujący komunikat:

-bash: fork: Resource temporarily unavailable

Maksimum powinno być wystarczająco niskie, aby w razie zaatakowania maszyny przez wielu użytkowników naraz pozostawić wystarczającą ilość wolnych zasobów na uniknięcie katastrofy.

Linki

Polecane

Byte my code

0 70
W tym roku obchodzimy 5. jubileuszową edycję znanej i cenionej konferencji Byte My Code powered by UBS. Na...
Konferencje

0 113