Skip to content

Instantly share code, notes, and snippets.

@kpodp0ra
Last active June 1, 2025 15:10
Show Gist options
  • Select an option

  • Save kpodp0ra/ce98db1a7bb18cfc7525658952d92157 to your computer and use it in GitHub Desktop.

Select an option

Save kpodp0ra/ce98db1a7bb18cfc7525658952d92157 to your computer and use it in GitHub Desktop.
🐚 Bash dla ludzi: praktyczna ściąga do pisania skryptów

Wypisywanie tekstu

echo "Hello, World!"
echo -n "Hello, World!"  # Brak nowej linii na końcu, przydatne w pipach

echo $'Nowa\nLinia'  # Wsparcie znaków specjalnych, np. \n

# kotek albo conCATination — wyświetla zawartość pliku albo łączy dwa pliki
cat nazwapliku

Data i godzina

date +"%d/%m/%y %H:%M:%S"

Wykorzystam tę sytuację, aby pokazać jedną sztuczkę. W tym formacie pojedyncze cyfry są prefixowane zerem (04), a te będą interpretowane przez basha jako zapis oktalny.

Można wymusić zapis decymalny przez 10#:

czas=0
czas=$(( $czas + 10#$(date +'%S') ))
czas=$(( $czas + 60 * 10#$(date +'%M') ))
czas=$(( $czas + 60 * 60 * 10#$(date +'%H' ) ))

Tworzenie linków symbolicznych (ln -s)

Link symboliczny to „skrót” do innego pliku:

ln -s /etc/nginx/nginx.conf nginx.conf-link
ln -s [oryginalny_plik] [nazwa_linka]

💡 Myśl o tym tak: nazwa_linka wskazuje NA oryginalny_plik.


Przeglądanie plików i katalogów (ls, du, df)

ls -l  # Wyświetla pliki w formie listy (sortowanie alfabetyczne)
ls -R  # Rekurencyjnie (czyli także z podkatalogami)
ls --sort=size   # Sortuj po rozmiarze
ls --sort=time   # Sortuj po dacie modyfikacji
ls --reverse     # Odwrotna kolejność sortowania

Wygląd ls -l:

-rw-r--r-- 1 user group 1234 May 30 12:00 filename.txt
    │        │     │      │        │           └─ Nazwa pliku
    │        │     │      │        └───────────── Czas modyfikacji
    │        │     │      └────────────────────── Rozmiar
    │        │     └───────────────────────────── Grupa
    │        └─────────────────────────────────── Właściciel
    └──────────────────────────────────────────── Prawa dostępu

Wygląd ls -R:

.:
folder
plik1.txt
plik2.txt

./folder:
plik3.txt

basename

basename "$ARG"

Usuwa początkowe ./ albo inne ścieżki — zostaje sama nazwa pliku.

du – disk usage, rozmiary:

du --all                 # Wszystkie pliki i katalogi
du                       # Tylko katalogi
du --summarize przyklad  # Podsumowanie rozmiaru, pokazuje tylko rozmiar z argumentu

df – disk free, ile mamy miejsca?

df . /

System plików       1K-bl     użyte   dostępne %uż. zamont. na
/dev/nvme1n1p2 3844245864 147406292 3501487852   5% /

Sortowanie danych (sort, uniq, cut, wc)

sort           # Alfabetycznie
sort -n        # Numerycznie
sort -h        # Numerycznie z rozmiarami (np. 10K, 5M)
sort -r        # Od końca

uniq – wykrywanie duplikatów:

uniq
uniq --count

cut – wycinanie kolumn:

cut -d ' ' -f1,4-6  # Dziel po spacji i weź kolumny
cut -c5-            # Od 5 znaku do końca
cut -c0-5           # Od początku do 5 znaku

expr – wyrażenia i substringi:

INDEX_D=$(expr index "$*" d)  # Znajdź indeks pierwszego wystąpienia znaku 'd' w zmiennej E
expr substr "$*" 1 "$INDEX_D"  # Wytnij substring od 1 do INDEX_D

head, tail – przycinanie linii:

head -n 10
tail -n 10

tac, rev – odwracanie linii i znaków:

cat
tac
rev

Przykład użycia rev do odwrócenia znaków w linii:

echo "$PWD" | rev | cut -d '/' -f1 | rev

wc – policz mi to:

wc --chars
wc --words
wc --lines

Matchowanie i regexy (egrep, expr, [[ =~ ]])

egrep -o "REGEX"
egrep --count "REGEX"
egrep --invert-match
egrep --count --invert-match
egrep --max-count=N

-o zwraca tylko część która matchuje regex, w przeciwnym razie regex łapie całą linię

Sprawdzanie, czy tekst pasuje:

expr "a" : "^a$"
expr match "a" "^a$"

tekst="ab"
if [[ $tekst =~ ^a ]]; then
  echo "Zaczyna się na a"
fi

Zmienna $BASH_REMATCH[0] pomaga wyciągnąć rzeczy z regexa.


Transformacje tekstu (tr, fold)

tr 'a-z' 'A-Z'   # Małe → wielkie litery
tr -d '0-9'      # Usuń cyfry
tr -s ' '        # Zredukuj duplikaty spacji
tr -s 'a-z'      # Zredukuj duplikaty liter
fold --width=1   # Zawija do jednej litery na linię

Pętle i warunki (for, if, (( )))

Pętla liczbowo:

for i in {1..5}; do
  echo "$i"
done

Pętla po argumentach

IFS=$' \t\n'  # domyślny separator pól (np. w pętlach for)

Gdy chcemy iterować po separatorze pól, zmienna nie może być w cudzysłowie (for arg in $ZMIENNA).

Przykład:

./skrypt "Hello darkness", my friend.

Używając for arg in $* da:

  1. Hello darkness,
  2. my
  3. friend.

Wyjątek: $@ jest specjalnym operatorem, który będzie wstawiał " " między argumentami, przez co jest idealny tutaj do pętli.

Używając for arg in "$@" da:

  1. Hello
  2. darkness,
  3. my
  4. friend.

Warunki (liczby i teksty):

Dlaczego nie lubię warunków z użyciem (( ))

a="foo"
foo=10

echo $(( a ))   # Bash "patrzy" na a, widzi "foo", więc podstawia wartość foo, czyli 10

Gdy zapomnę sprawdzić, czy zmienna jest liczbą, bash szuka wartości zmiennej o nazwie równej temu stringowi To może doprowadzić do licznych błędów.

Dlatego wolę [[ -eq, -gt, -lt, -ne, -ge, -le ]]

if [[ A -gt B ]]; then
  echo "Git"
fi

if [[ "$A" = "$B" ]]; then
  echo "Równe"
fi

Testy plików (-d, -e, -f, -L, itd.)

-d FILE  # Czy katalog?
-a/-e FILE  # Czy istnieje?
-f FILE  # Czy zwykły plik?
-L FILE  # Czy link symboliczny?
-r FILE  # Czy czytelny?
-w FILE  # Czy zapisywalny?
-x FILE  # Czy wykonalny?

Zmienne i argumenty

echo "$1"        # pierwszy argument
echo "$@"        # wszystkie jako array
echo "$*"        # wszystkie jako jeden string
echo "$#"        # liczba argumentów
echo "$?"        # kod ostatniego błędu
shift            # przesuwa argumenty w lewo
A=$(pwd)
i=$((1 + i))

Czytanie od użytkownika

read -r A
echo "$A"

Szukanie (find)

⚠️ Find nie wspiera regexa, tylko glob patterny!

find . -name "*.txt" -exec echo "{}" \;

Czytanie z standardowego wejścia

Czyta standardowe wejście i przekazuje je do komendy jako argumenty dzieląc po spacji i nowych liniach.

xargs [komenda]

# Domyślna komenda to "echo", można więc zrobić tak
WEJSCIE=$(xargs)

# To teraz dzielmy po nowych liniach
WEJSCIE=$(xargs -d $'\n')
# Komenda bedzie wygladala tak: echo "Pierwsza linia" "Druga linia"

# Ale chcemy aby wykonało pare komend echo, ustawiamy limit 1
WEJSCIE=$(xargs -d $'\n' -n 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment