Linux: Skripty - cykly



1. Cyklus for

Vypíše čísla od 1 do 10 včetně:

for ((i=1; i<=10; i++)); do
  echo $i
done

Zjednodušený zápis předchozího cyklu:

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

Nebo i takto:

for i in {20..0..2}; do
  echo $i
done

2. Cyklus for II

Cyklus for může do proměnné postupně dosazovat i seznam hodnot:

Čísla:

for d in 10 20 30 40 50
do
  echo $d
done

Znaky/řetězce:

for c in P R A H A Brno
do
  echo $c
done

Seznam souborů:

for f in /etc/passwd /etc/group
do
  echo "Soubor $f ma $(wc -l $f | awk '{print $1}') radku."
done

3. Cyklus for III

V bashi nemusí být cyklus for vždy jen s předem známým počtem opakování. Ukázkový skript vypíše všechny soubory v adresáři s příponou .sh.

for file in *.sh
do
  echo $file
done

☝️ Na https://linuxize.com/post/bash-for-loop/ si prostudujte další možnosti. Jsou tam i příklady s příkazy break a continue, které se běžně nepoužívají.

4. Cyklus while

Cyklus while má standardní syntaxi i chování. Bude se opakovat, dokud bude podmínka TRUE (1):

cislo=0

while [ $cislo -ne 100 ]
do
  cislo=$(($cislo + 10))# 
  echo $cislo
done

☝️ Na https://linuxize.com/post/bash-while-loop/ jsou další ukázky. Prostudujte je a vyzkoušejte.

5. Další konstrukce

Kromě zde představených rozhodovacích konstrukcí if elif else, for a while má bash ještě další:

Poslední dva typy jsou využitelné zejména pro interakci s uživatelem.

6. Argumenty skriptu

Spouštěný skript může převzít i jeden nebo více argumentů. Je to běžný koncept téměř všech příkazů: cat, ls, mkdir... Tyto argumenty jsou uloženy v proměnných prostředí:

Skript očekává jeden nebo více parametrů jako argument(y) spouštěného skriptu. Může se jednat o text, číslo, cestu k souboru nebo adresáři:

$ ./porovnej.sh fileA fileB
$ ./soucet.sh 20 10
$ ./najdi.sh ~/soubor.txt abcd

Příklad použití:

#!/bin/bash

if [ "$#" != 2 ]
then
  echo "Použití: $0 arg1 arg2"
  exit 1
fi

echo "První argument je $1"
echo "Druhý argument je $2"

exit 0

Tento skript očekává přesně dva argumenty. Jestliže bylo předáno více nebo méně, vytiskne zprávu o použití a skončí s chybou (exit 1). Proměnná $0 obsahuje samotný název skriptu. Jestliže byly oba argumenty předány, skript je vypíše a vrátí 0 (korektní ukončení).

7. Speciální znaky # a %

Konstrukce odstraní z názvu souboru/adresáře zadaný řetězec podle vzoru:

${nazev_souboru#odstranit}
${nazev_souboru%odstranit}

Znak # odstraní řetězec odstranit od začátku (zleva), zatímco znak % od konce (zprava).

Příklady:

var=program.txt

var=${var#pro}    # převede program.txt na gram.txt
var=${var%.txt}   # odstraní příponu .txt
var=${var%txt}sh  # převede program.txt na program.sh

Poslední příklad nahradí příponu txt na sh tak, že nejprve odstraní původní a pak doplní do názvu znaky sh. Tečka a vše nalevo zůstává beze změny. Typickým využitím je hromadná změna přípon více souborů pomocí cyklu.

Snadno jde také z názvu souboru extrahovat samotný název (bez přípony) nebo naopak pouze příponu (bez tečky):

nazev="${var%.*}"
pripona="${var##*.}"

8. Cvičení

8.1. 💾 Kontrola vstupních dat (overeni.sh)

Napište skript overeni.sh, který vyzve uživatele, aby zadal své platné uživatelské jméno. Pokud jej zadá správně, vypíše uvítání. Pokud ne, vyzve uživatele znovu.

8.2. 💾 Je zadaný rok přestupný? (rok.sh)

Historie přestupných dnů sahá do starověkého Egypta. Používal se už v roce 238 př. n. l. V Evropě jej zavedl až papež Řehoř XIII. bulou Inter gravissimas v roce 1582. Různé země a církve však zavedly tuto změnu až později. V tomto našem tak zvaném "gregoriánském" kalendáři je vkládán přestupný den každý rok, který je buď dělitelný čtyřmi beze zbytku, avšak s výjimkou celých století nebo je beze zbytku dělitelný 400.

Napište skript rok.sh, který pro zadaný rok vypíše, zda je nebo není přestupný. Bude se vám hodit vzor složeného výrazu, který má v bashi poněkud složitější syntaxi:

((r % 4 == 0) && (r % 100 != 0)) || (r % 400 == 0)

8.3. 💾 Hromadný převod dat do CSV (csv.sh)

Stáhněte a rozbalte podkladové soubory:

$ wget http://www.edumach.cz/files/csv.tar.gz 
$ tar xvfz csv.tar.gz 

(xvfz = extract, verbose, file, zip)

V adresáři csv se nachází 30 souborů s názvy xaa, xab, xac... obsahující fiktivní data osob netradičně oddělených hvězdičkou.

Napište skript csv.sh, který všechny znaky * ve všech souborech adresáře csv nahradí znaky ; (středník). Dále ke každému souboru přidá příponu .csv (xaa.csv, xab.csv, xac.csv...). Obě operace vykoná skript pomocí vhodného cyklu. V jakém pořadí je na vás.

Dále zajistěte, aby opakovaným spouštěním skriptu již nepřidával další příponu (např. xaa.csv.csv, xaa.csv.csv.csv).

8.4. 💾 Filtrovaný výpis souborů (filtr_read.sh)

Stáhněte si a rozbalte podkladové soubory:

$ wget http://www.edumach.cz/files/folders.tar.gz 
$ tar xvfz folders.tar.gz 

V adresáři folders se nachází 198 souborů různých názvů, formátů a velikostí. Napište skript filtr_read.sh, který vypíše názvy souborů a jejich velikosti (v tomto pořadí) jednoho určeného formátu. Ten skript převezme příkazem read.

Ukázka možného výstupu:

file_A.txt 200 
file_B.txt 35
file_C.txt 4
...

Nápověda: Podrobný výpis souborů je "tabulka", kde jsou položky oddělené mezerou.
Například příkaz awk '{print $2 $3}' vypíše pouze druhý a třetí "sloupec".

8.5. 💾 Filtrovaný výpis souborů (filtr_arg.sh)

Stáhněte si a rozbalte podkladové soubory:

$ wget http://www.edumach.cz/files/folders.tar.gz 
$ tar xvfz folders.tar.gz 

V adresáři folders se nachází 198 souborů různých názvů, formátů a velikostí. Napište skript filtr_arg.sh, který vypíše názvy souborů a jejich velikosti (v tomto pořadí) jednoho určeného formátu. Ten skript převezme jako argument.

Ukázka možného výstupu:

./filtr_arg.sh txt

file_A.txt 200 
file_B.txt 35
file_C.txt 4
...

Nápověda: První argument skriptu je v proměnné $1. Podrobný výpis souborů je "tabulka", kde jsou položky oddělené mezerou - příkaz awk '{print $2 $3}' vypíše pouze druhý a třetí "sloupec".

8.6. 💾 Úklid souborů podle přípony (uklid.sh)

Stáhněte si a rozbalte podkladové soubory:

$ wget http://www.edumach.cz/files/folders.tar.gz 
$ tar xvfz folders.tar.gz 

V adresáři se nachází 198 souborů různých názvů, formátů a velikostí. Napište skript uklid.sh, který přesune všechny soubory z adresáře folders do adresáře ~/uklizeno. V něm je skript roztřídí podle jejich přípony. Příklad: Skript narazí na soubor s příponou .txt. V adresáři ~/uklizeno vytvoří adresář txt a přesune do něj všechny .txt soubory. Takto roztřídí i ostatní soubory.