Láttuk már, hogyan írjunk egyszerű parancsokat, ahol a parancsot argumentumok követik. Most nézzük meg, hogyan hozhatunk létre összetettebb parancsokat egyszerű parancsok összefűzésével.
Mielőtt belekezdünk, egy gyors bevezető a bemenetről és a kimenetről.
A folyamatoknak „szabványos I/O-csatornáik” vannak.
A tr parancs erre nagyon tiszta példa.
Nem tesz mást, mint beolvassa a szöveget a bemenetéről, karakterátírásokat hajt végre, és a kapott szöveget a kimenetére írja.
A „stdio” csatornák kezeléséről később, a tanterv során még többet olvashatsz.
Ez a shell-programozás egyik „legnagyobb dobása”. A csővezetékekkel kifinomult átalakításokat végezhetsz egy szövegfolyamon.
Így állíthatod elő a felhasználók rendezett listáját:
cat /etc/passwd | cut -d : -f 1 | sort
A cső szimbóluma (|) összeköti az egyik parancs kimenetét egy másik parancs bemenetével.
A cut a cat kimenetét olvassa, a sort pedig a cut kimenetét.
Alapértelmezés szerint a csővezeték minden parancsa külön alhéjban fut. (Az alhéj egy gyermekfolyamat, amely az éppen futó shell másolata.)
A csővezetékek futtatásának teljesítményköltsége van.
Ha hosszú, hasonló parancsokból álló csővezetékeid vannak, fontold meg, hogy egyetlen parancsba vond őket össze.
Például a több grep, cut, sed, awk és tr példányt használó csővezetékek a hatékonyság érdekében általában egyetlen awk paranccsá vonhatók össze.
A csővezeték kilépési állapota a csővezeték utolsó parancsának kilépési állapota. Ez azt jelenti, hogy ha egy korábbi parancs sikertelen volt, de az utolsó sikeres, akkor az egész csővezeték kilépési állapota nulla.
Létezik egy shell-beállítás, amely ezt megváltoztathatja;
ha a „pipefail” beállítás be van kapcsolva (a set -o pipefail paranccsal), akkor a csővezeték kilépési állapota a következő lesz:
A parancslista csővezetékek sorozata, amelyeket ; (vagy sortörés), && vagy || választ el egymástól.
A; B olyan parancslista, ahol a B az A befejeződése után fut le.A && B esetén a B csak akkor fut le, ha az A sikeres (nulla állapottal lép ki).A || B esetén a B csak akkor fut le, ha az A sikertelen (nem nulla állapottal lép ki).Egy parancslista kilépési állapota a benne utolsóként lefutott parancs kilépési állapota.
A && és || operátorok láncba fűzhetők, így a következő parancs az előtte lévő parancsok állapota alapján, feltételesen fut le.
Például
A && B && C && D || E
Használd ezeket a logikai operátorokat mértékkel. Gyorsan olvashatatlan kódhoz vagy nehezen átlátható logikához vezethetnek.
Például azt hiheted, hogy ezek ugyanazt jelentik:
if A; then B; else C; fi
A && B || C
A különbség: mikor fut le a C?
Íme néhány példa, ahol a parancslisták leegyszerűsíthetik a kódot.
Tegyük fel, hogy van egy adatfájlod, amely háromszögekre vonatkozó adatokat tartalmaz, és egy háromszöget három különálló sor ábrázol, amelyek a háromszög oldalait tartalmazzák.
$ cat triangle.dat
3
4
5
9
12
14
Használhatsz egy while-ciklust, amelynek feltétele három külön read parancs:
while read a && read b && read c; do
if is_pythagorean "$a" "$b" "$c"; then
echo "$a:$b:$c is pythagorean"
else
echo "$a:$b:$c is not pythagorean"
fi
done < triangle.dat
Feltéve, hogy az is_pythagorean egy olyan parancs, amely megállapítja, hogy a három oldal kielégíti-e a Pitagorasz-egyenletet, a kimenet ez lenne:
3:4:5 is pythagorean
9:12:14 is not pythagorean
Sok programozási nyelvben létezik az állításnak egy olyan formája, ahol kivétel keletkezik, ha egy feltétel nem teljesül
assert(user == "Administrator", "wrong user");
Ezt a funkciót a Bashben egy VAGY operátorral szimulálhatjuk:
die () { # a little convenience function
echo "$*" >&2
exit 1
}
[[ $user == "Administrator" ]] || die "wrong user"
[[ $password == "secret!" ]] || die "incorrect password"
A hosszú parancslisták meglehetősen gyorsan olvashatatlanná válnak. A sortörések bő használata sokat segíthet.
Vegyük ezt a példát, ahol egy szót adunk egy tömbhöz, ha két feltétel teljesül.
[[ "$word" != "$topic" ]] && [[ "$key" == "$(sorted "$topic")" ]] && anagrams+=("$candidate")
A Bashben sortörést szúrhatsz be egy cső vagy egy logikai operátor után.
[[ "$word" != "$topic" ]] &&
[[ "$key" == "$(sorted "$topic")" ]] &&
anagrams+=("$candidate")
Az operátor azonban a sor végén könnyen elkerülheti a figyelmedet. Ha sorfolytatást használsz, az operátort a sor elejére teheted, így nyilvánvalóbb lesz, hogy a lista folytatódik:
[[ "$word" != "$topic" ]] \
&& [[ "$key" == "$(sorted "$topic")" ]] \
&& anagrams+=("$candidate")
A sorfolytatás a „backslash” és a „sortörés” kétkarakteres sorozata (\ + \n).
Amikor a Bash meglátja ezt a sorozatot, egyszerűen eltávolítja a kódból, és ezzel az aktuális sort a következő sorral folytatja.
Ügyelj rá, hogy a backslash és a sortörés között ne legyen szóköz.
Íme egy másik példa
printf "%s\n" "${numbers[@]}" | bc --mathlib | sort --general-numeric-sort
vagy
printf "%s\n" "${numbers[@]}" \
| bc --mathlib \
| sort --general-numeric-sort