Systemy operacyjne · skrypty powłoki · rozwiązania sprawdzone w terminalu
Uwaga (z treści kolokwium): wyżej oceniane są rozwiązania z użyciem struktur for, if, while itd. niż pojedyncze polecenie, które być może rozwiązuje problem. Poniższe rozwiązania celowo używają pętli i instrukcji warunkowych.
KOLOKWIUM 1
Kolokwium 1 · Zadanie 14 p
Napisz skrypt (lub polecenie), który wypisze nazwy tych plików z katalogu bieżącego, których treść nie zawiera na początku linii tekstu /*main*/. Mają być wypisane wyłącznie nazwy.
Skrypt k1z1.sh
#!/bin/bash
# K1 Z1: nazwy plików z biezacego katalogu, ktore NIE zawieraja
# na poczatku linii tekstu /*main*/ (wypisujemy tylko nazwy).
for f in *; do
if [ -f "$f" ]; then
if ! grep -q '^/\*main\*/' "$f"; then
echo "$f"
fi
fi
done
Jak to działa
Pętla for po pozycjach katalogu; [ -f "$f" ] ogranicza do zwykłych plików. grep -q '^/\*main\*/' sprawdza, czy istnieje linia zaczynająca się od /*main*/ (kotwica ^, gwiazdki zabezpieczone \*). Warunek if ! grep -q ... wybiera pliki, które tego wzorca nie mają.
Weryfikacja (uruchomione w terminalu)
✅ Katalog testowy: a.c = /*main*/ w 1. linii, b.c = /*main*/ w 2. linii (nadal na początku linii), c.txt bez wzorca, d.c = /*main*/ (z wcięciem). Wynik: c.txt, d.c ✓ (b.c pominięty, bo ma wzorzec na początku linii).
Kolokwium 1 · Zadanie 26 p
Napisz skrypt, który zapisze do pliku P te spośród swoich argumentów, które są katalogami zawierającymi co najwyżej 11 pozycji (dowolnych plików lub katalogów, również ukrytych). Nazwa pliku P podana z klawiatury. W P zapisujemy nazwę katalogu i ilość pozycji.
Skrypt k1z2.sh
#!/bin/bash
# K1 Z2: zapisz do pliku P te argumenty, ktore sa katalogami majacymi
# co najwyzej 11 pozycji (rowniez ukrytych). Nazwe P podajemy z klawiatury.
echo -n "Podaj nazwe pliku P: "
read P
: > "$P"
for d in "$@"; do
if [ -d "$d" ]; then
n=$(ls -A "$d" | wc -l) # -A: wszystko oprocz . oraz ..
if [ "$n" -le 11 ]; then
echo "$d $n" >> "$P"
fi
fi
done
Jak to działa
Nazwę P pobieramy przez read. : > "$P" tworzy/czyści plik wynikowy. Dla każdego argumentu [ -d ] sprawdza, czy to katalog. Liczbę pozycji liczymy ls -A — opcja -A pokazuje pliki ukryte, ale pomija. i .. (które nie są „pozycjami”). [ "$n" -le 11 ] to warunek „co najwyżej 11”.
Weryfikacja (uruchomione w terminalu)
✅ Argumenty: small (5 plików + 1 ukryty = 6), big (15), empty (0), zwykly (plik). Podano P=wynik.txt. Zawartość P: small 6 i empty 0 ✓ (big i zwykly pominięte).
Kolokwium 1 · Zadanie 3 — wersja 213 p
Skrypt pobiera trzy argumenty PLIKWEJSCIOWY, PLIKWYJSCIOWY1, PLIKWYJSCIOWY2 i przepisuje wszystkie liczby do PLIKWYJSCIOWY1, a ciągi różne od liczb do PLIKWYJSCIOWY2 (zachowując układ linii). Wersja 2: dopuszczamy elementy wieloznakowe.
Skrypt k1z3_v2.sh
#!/bin/bash
# K1 Z3 (wersja 2 - dopuszczamy tokeny wieloznakowe):
# $1 wejscie, $2 <- liczby, $3 <- ciagi rozne od liczb (zachowujac uklad linii).
IN="$1"; O1="$2"; O2="$3"
: > "$O1"; : > "$O2"
while read -r line; do
nums=""; strs=""
for tok in $line; do
if [[ "$tok" =~ ^[0-9]+$ ]]; then
nums="$nums $tok"
else
strs="$strs $tok"
fi
done
echo "${nums# }" >> "$O1"
echo "${strs# }" >> "$O2"
done < "$IN"
Jak to działa
Pętla while read -r line czyta plik linia po linii. Wewnętrzna pętla for tok in $line dzieli linię na słowa. Test [[ "$tok" =~ ^[0-9]+$ ]] rozpoznaje liczbę (same cyfry). Zbieramy je do zmiennych nums/strs, a ${nums# } usuwa wiodącą spację. Dla każdej linii wejścia powstaje po jednej linii w obu plikach — dzięki temu układ wierszy jest zachowany.
Weryfikacja (uruchomione w terminalu)
✅ Wejście: 1 2 3 a 4 5 / 9 2 3a3 b / 1 2 a l a i o l a / 9 2 c. OUT1: 1 2 3 4 5 / 9 2 / 1 2 / 9 2. OUT2: a / 3a3 b / a l a i o l a / c ✓
Kolokwium 1 · Zadanie 3 — wersja 113 p
Jak wyżej, ale jeżeli pojawi się jakikolwiek ciąg dłuższy niż 1 znak, skrypt ma się zakończyć, a pliki wyjściowe powinny zostać skasowane. (Plik wejściowy powinien zawierać pojedyncze znaki oddzielone spacją.)
Skrypt k1z3_v1.sh
#!/bin/bash
# K1 Z3 (wersja 1): jesli pojawi sie token dluzszy niz 1 znak -> przerwij
# i skasuj pliki wyjsciowe.
IN="$1"; O1="$2"; O2="$3"
: > "$O1"; : > "$O2"
while read -r line; do
for tok in $line; do
if [ ${#tok} -gt 1 ]; then
echo "Blad: token wieloznakowy '$tok' - przerywam."
rm -f "$O1" "$O2"
exit 1
fi
done
nums=""; strs=""
for tok in $line; do
if [[ "$tok" =~ ^[0-9]+$ ]]; then
nums="$nums $tok"
else
strs="$strs $tok"
fi
done
echo "${nums# }" >> "$O1"
echo "${strs# }" >> "$O2"
done < "$IN"
Jak to działa
Przed przepisaniem każdej linii dodatkowa pętla for sprawdza [ ${#tok} -gt 1 ] (długość tokenu). Jeśli któryś token ma więcej niż 1 znak — komunikat, rm -f plików wyjściowych i exit 1. Dalsza część (przepisywanie) jest identyczna jak w wersji 2.
Weryfikacja (uruchomione w terminalu)
✅ Dane z tokenem ala → wypisuje „Blad: token wieloznakowy 'ala'”, exit=1, oba pliki wyjściowe skasowane (NIE istnieją) ✓. Dane jednoznakowe → przepisuje poprawnie, exit=0 ✓
KOLOKWIUM 2
Kolokwium 2 · Zadanie 1—
Napisz skrypt, który wypisze nazwy tych katalogów z katalogu bieżącego, które zawierają co najmniej jeden plik do odczytu.
Skrypt k2z1.sh
#!/bin/bash
# K2 Z1: nazwy katalogow z biezacego katalogu zawierajacych
# co najmniej jeden plik do odczytu.
for d in */; do
d="${d%/}"
if [ -d "$d" ]; then
found=0
for f in "$d"/*; do
if [ -f "$f" ] && [ -r "$f" ]; then
found=1
break
fi
done
if [ "$found" -eq 1 ]; then
echo "$d"
fi
fi
done
Jak to działa
Zewnętrzna pętla for d in */ iteruje po podkatalogach (${d%/} ucina końcowy ukośnik). Wewnętrzna pętla szuka w katalogu pliku spełniającego [ -f "$f" ] && [ -r "$f" ] (zwykły plik + prawo odczytu). Po znalezieniu ustawiamy found=1 i break. Katalog trafia na wyjście tylko gdy taki plik istnieje.
Weryfikacja (uruchomione w terminalu)
✅ Katalogi: withfile (czytelny plik), noread (plik z chmod 000), emptyd (pusty). Wynik: withfile ✓ (noread i emptyd pominięte).
Kolokwium 2 · Zadanie 2—
Napisz skrypt, który wypisze te spośród swoich argumentów, które są plikami zawierającymi co najmniej 2 wystąpienia słowa CPU. Z przodu słowa musi być spacja, a z tyłu spacja, kropka lub przecinek.
Skrypt k2z2.sh
#!/bin/bash
# K2 Z2: te argumenty, ktore sa plikami zawierajacymi >= 2 wystapienia
# slowa CPU (z przodu spacja, z tylu spacja/kropka/przecinek).
for f in "$@"; do
if [ -f "$f" ]; then
n=$(grep -o ' CPU[ .,]' "$f" | wc -l)
if [ "$n" -ge 2 ]; then
echo "$f"
fi
fi
done
Jak to działa
Dla każdego argumentu-pliku liczymy wystąpienia wzorca grep -o ' CPU[ .,]': spacja przed, a po literach jeden ze znaków [spacja . ,] (klasa znaków). -o wypisuje każde trafienie osobno, więc wc -l je zlicza. Warunek [ "$n" -ge 2 ] = „co najmniej 2”. Uwaga: klasa [ .,] to spacja, kropka lub przecinek.
Weryfikacja (uruchomione w terminalu)
✅ Pliki: f1 = „ma CPU. i CPU, tutaj” (2×), f2 = „jedno CPU tutaj” (1×), f3 = „xCPU. yCPU.” (brak spacji z przodu). Wynik: f1 ✓
Kolokwium 2 · Zadanie 3—
Skrypt pobiera nazwę pliku jako pierwszy argument i wyznacza ilość wszystkich cyfr i liter w pliku oraz sumę wszystkich liczb. Plik może mieć zmienną liczbę linii i elementów; nie ma tokenów mieszających cyfry z literami.
Skrypt k2z3.sh
#!/bin/bash
# K2 Z3: policz cyfry i litery w pliku ($1) oraz sume wszystkich liczb.
F="$1"
digits=0; letters=0; sum=0
while read -r line; do
for tok in $line; do
if [[ "$tok" =~ ^[0-9]+$ ]]; then
sum=$((sum + 10#$tok))
digits=$((digits + ${#tok}))
else
letters=$((letters + ${#tok}))
fi
done
done < "$F"
echo "Plik $F zawiera $digits cyfr oraz $letters liter."
echo "Suma wszystkich liczb wynosi $sum"
Jak to działa
Podwójna pętla while/for przechodzi po wszystkich tokenach. Token będący liczbą ([[ =~ ^[0-9]+$ ]]): dodajemy jego wartość do sum (zapis 10#$tok wymusza system dziesiętny — chroni przed interpretacją np. 010 jako ósemkowej) i dokładamy ${#tok} cyfr. Token literowy: dokładamy ${#tok} liter. Na końcu wypisujemy wynik.
Weryfikacja (uruchomione w terminalu)
✅ Wejście z treści zadania (3 linie). Wynik: Plik in.txt zawiera 15 cyfr oraz 16 liter. / Suma wszystkich liczb wynosi 145 — dokładnie zgodny z oczekiwanym ✓