A szövegszerkesztő – vi

Ma egy szövegszerkesztőről van egy körülbelüli elképzelésünk. Na a vi nem ilyen. 🙂

A vi <filenév> paranccsal indul a szövegszerkesztő. Ilyenkor alapban parancs módban vagyunk. 🙂 Billentyűkkel lehet eljutni a szerkesztői módba. Szerkeszteni ugyanis szerkesztői módban lehet. 🙂 “O” (shift+o) billentyűvel egy új sort szerkeszthetünk az aktuális pozíció fölött – ezek között a nyilakkal közlekedhetünk, esetleg “:<sorszám>“-mal, parancs módban. “o” billenyűvel az aktuális pozíció alatt nyílik új sor. “i” betűvel az aktuális pozícióban tudunk beszúrni szöveget, “a” betűvel hozzáfűzhetünk szöveget az aktuális pozíciótól (append). 🙂 Szerkesztői módból az “esc” billentyűvel tudunk parancs módba visszalépni.

Hogy ez miért jó? Mert szinte minden terminálban, bármely UNIX és Linux rendszerben installálva van vagy installálható. Egyébként nem muszáj használni (“:h” -val segítség kérhető, amiből “:q“-val lehet kilépni :)). Van az editor vagy nano, ami jobb műkedvelőknek. Az ctrl szekvenciákkal vezérelhető. 🙂 Hogy mégis miért jó? A jó programozó tud vi-ban, akár osztott ablakban, szintaxis-kiemeléssel, kizárólag billentyűk lenyomásával akármit írni (!).

Nézzük tovább a használatot. Kilépés, ha nem módosítottunk – ellenkező esetben hibaüzenetet kapunk – a “:q“, kilépés módosítások elvetésével “:q!“. Kilépés mentéssel “:wq” vagy “shift+zz“. 🙂

Nem írnám le a teljes kezelést, az szorgalmi++. 🙂 Még részleteznék pár apróságot. Hogyan lehet keresni? Egész egyszerűen parancs módban “/<keresendő_sztring>” – “n” betűvel lehet lépkedni előre, “shift+n“-nel visszafelé a találatok között. Még fontos lehet az “undo”, visszavonás funkció, ez egész egyszerűen az “u” parancs. Egy sort a “dd” paranccsal tudunk törölni. Három sort “3dd” paranccsal. 🙂 Jó, nem?

Akkor nézzük a továbbiakban felsorolásszerűen.

Ugrás a sor végére: “$
Ugrás a sor elejére: “0
Beolvas egy file-t. és beszúrja az adott pozcióba: “:r <filenév>
Képernyő megosztása: “:split <filenév>
Képernyő függőleges megosztása: “:vsplit <filenév>
Navigáció a két osztott képernyő között: “ctrl+ww
Sor másolása: másolás: “yy” (yank), kivágás: “dd” (delete), beillesztés pozíció előtt: “P“, pozíció után: “p” (paste)
Kijelölés másolásra karakterenként: “v“, soronként: “V“, utána “y” vagy “d“, végül “p” vagy “P” a beillesztéshez, osztott képernyők között is működik 🙂
File vége: “shift+g“, eleje “g
Egy szó előre: “w“, hátra: “b

És akkor beszéljünk még egy dologról. Minden editor tudja a keresés és cserét. Nézzük meg ezt vi-ban. A parancs formátuma a következő: “:%s/<keresendő>/<cserélendő>/“, illetve ha minden sorban többször előfordulhat a keresendő és cserélendő sztring, akkor “:%s/<keresendő>/<cserélendő>/g” – a végén van egy “g“. Itt említeni illik a keresett kifejezéssel kapcsolatban az ún. reguláris kifejezéseket (reguar expressions). Ez az a formátum, ahogyan a keresendő sztring megadható. A sed parancs egyébként ugyanilyen formátummal működik, file(ok)-ban cserél sztringeket. (A sztring karakterfüzér.) RegExp részletek az alábbi link alatt. 🙂

http://vbence.web.elte.hu/regex_leiras.html

A végére még egy “elvetemült” dolog. 🙂 Lehet a bash shell-ünket is vi módban használni. Egyébként pl. az előző parancs előhozására a fel nyilat használhatjuk. Igazából a fel/le nyilakkal kereshetünk az előzőleg beírt parancsok között, sőt: a shell-ünk el is menti a .bash_history file-ba az előzőleg beírt parancsainkat, így ha újra kinyitjuk a shell-t is emlékezni fog a parancsainkra. 🙂 Fontos funkcionalitás még “sima” shell-ben az ugrás a sor elejére “ctrl+a“, sor végére “ctrl+e“, továbbá aktuális parancs megszakítása “ctrl+c“. De mi is az a vi módú shell? A home könyvtáramban létrehoztam a .inputrc file-t, a következő tartalommal.

gvamosi@gergo1:~$ cat .inputrc
set editing-mode vi

Újra “beléptem” a shell-be (kilépés ctrl+d-vel, és újraindítás). Innentől az “esc” billentyűvel parancsmódba kerülünk, vi parancsmódba. Minden ugyanúgy működik, ahogy vi-ban. Ez tényleg csak a legkeményebb admin-oknál van így beállítva. 😉

És hogy hogy lehet a szintaxis kiemelést (syntax highlight) bekapcsolni? Nálam, a Debian 10-ben elég egyszerűen. Nézzük.

gvamosi@gergo1:~$ sudo apt-get install vim
..
gvamosi@gergo1:~$ which vi
/usr/bin/vi
gvamosi@gergo1:~$ l /usr/bin/vi
lrwxrwxrwx 1 root root 20 Aug 26 2017 /usr/bin/vi -> /etc/alternatives/vi
gvamosi@gergo1:~$ l /etc/alternatives/vi
lrwxrwxrwx 1 root root 18 Oct 2 00:12 /etc/alternatives/vi -> /usr/bin/vim.basic

Telepítés (install) után az alapértelmezett vi editor a vim lesz, amiben a szintaxis kiemelés bekapcsolt. 🙂 Vi IMproved, a programmer’s text editor.

Debug – hibakeresés, bináris debug, kis lépések módszere, strace

Ha programozunk, debug-olnuk is kell, azaz hibát is kell keresnünk, mivel a hibátlan programozást még nem találták fel. Erre komplett fejlesztő eszközök vannak, melyek használatát itt nem részletezném. Maga a debug szó “bogártalanítást” jelent, és egy urbánus legendába hajló sztori az alapja. Az első számítógépek fizikai relékkel (jelfogókkal) működtek. Egy ilyen őskori gép egyszer elromlott, mivel bele ment egy bogár. 🙂 Azóta debug a hibakeresés.

Nézzük a programozó alap és egyben legvégső fegyverét, a bináris debug-ot. Ehhez binárisan kell gondolkodnunk. Működési elve igen egyszerű.

  1. Felezzük meg a kódunkat, kommentezzük ki a kód egyik felét.
  2. Ha megtaláljuk a hibát az egyik felében, és nem értünk a végére, akkor 1-es lépés (felezzük tovább a kódot). Ha a végére értünk, akkor megvan a hiba. 🙂
  3. Ha nincs benne hiba, akkor cseréljük fel a kikommentezett felet és a nem kikommentezett felet, majd 1-es lépés. 🙂

Látható, hogy nem bonyolult, legfeljebb időigényes. Hamar be lehet a segítségével korlátozni a hiba helyét egy-két sornyi kódra. A lépések száma a kettő hatványainak kitevője, ebben a matematikai mélységi kereséshez hasonlít. Ezzel a módszerrel még akkor is boldogulunk, ha több hiba is előfordul a kódban, mivel “brute force” az algoritmus. 🙂

Ja és hogy mit jelent a “kikommentezés”? Olyan kódrészlet, ami nem hajtódik végre, kisegítő információ a forráskódban a programozók számára (a forráskód általában lefordításra kerül, hogy a számítógép is “megértse”). Ahogy az eddigiekben látható, shell script-ben a hashmark # a sor elején vagy végén a megjegyés helye, C-ben, C++-ban és JAVA-ban pedig a blokk megjegyzés /* megjegyzés */ formátumú, illetve az egy sornyi megjegyés a // jelek után írandó.

A kis lépések módszere még egyszerűbb az előbbinél, és széles körűen alkalmazzák a fejlesztők. A lényege, hogy csak egy vagy legfeljebb pár sor új kódot adunk hozzá az addigiekhez programozás során, illetve csak egy újabb modult fűzünk hozzá, nem egyből egy maréknyit, és természetesen egyből tesztelünk. Így gyorsan kiderül, ha hibás kódot írtunk le, és nem kell három napot egyetlen hiba megtalálásával töltenünk! 🙂

Végül nézzük meg a strace használatát (miután apt-get-tel telepítettem). Ezzel a programmal a rendszerhívásokat és a jelzéseket írathatjuk ki egy tetszőleges program végrehajtása során. Vegyük az egyszerű alma.sh programot.

gvamosi@gergo1:~$ cat alma.sh
#!/bin/sh
ls --color -l

Meglepő lehet, de a kétsoros script hatalmas strace kimenetet generál! Nézzük meg a “nyomkövetés” eredményét.

gvamosi@gergo1:~$ strace alma.sh
execve("./alma.sh", ["alma.sh"], 0x7fffb90cb390 /* 39 vars */) = 0
brk(NULL) = 0x55ffa24e5000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=169286, …}) = 0
mmap(NULL, 169286, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f458d3ff000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260A\2\0\0\0\0\0"…, 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, …}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f458d3fd000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f458d23c000
mprotect(0x7f458d25e000, 1658880, PROT_NONE) = 0
mmap(0x7f458d25e000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f458d25e000
mmap(0x7f458d3a6000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f458d3a6000
mmap(0x7f458d3f3000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f458d3f3000
mmap(0x7f458d3f9000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f458d3f9000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f458d3fe580) = 0
mprotect(0x7f458d3f3000, 16384, PROT_READ) = 0
mprotect(0x55ffa169d000, 8192, PROT_READ) = 0
mprotect(0x7f458d450000, 4096, PROT_READ) = 0
munmap(0x7f458d3ff000, 169286) = 0
getuid() = 1000
getgid() = 1000
getpid() = 19358
rt_sigaction(SIGCHLD, {sa_handler=0x55ffa1693380, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f458d273840}, NULL, 8) = 0
geteuid() = 1000
brk(NULL) = 0x55ffa24e5000
brk(0x55ffa2506000) = 0x55ffa2506000
getppid() = 19355
stat("/home/gvamosi", {st_mode=S_IFDIR|0755, st_size=4096, …}) = 0
stat(".", {st_mode=S_IFDIR|0755, st_size=4096, …}) = 0
openat(AT_FDCWD, "./alma.sh", O_RDONLY) = 3
fcntl(3, F_DUPFD, 10) = 10
close(3) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
geteuid() = 1000
getegid() = 1000
rt_sigaction(SIGINT, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGINT, {sa_handler=0x55ffa1693380, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f458d273840}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f458d273840}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f458d273840}, NULL, 8) = 0
read(10, "#!/bin/sh\n\nls --color -l\n", 8192) = 25
stat("/usr/local/bin/ls", 0x7ffea163b940) = -1 ENOENT (No such file or directory)
stat("/usr/bin/ls", 0x7ffea163b940) = -1 ENOENT (No such file or directory)
stat("/bin/ls", {st_mode=S_IFREG|0755, st_size=138856, …}) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f458d3fe850) = 19359
wait4(-1, total 300
lrwxrwxrwx 1 gvamosi gvamosi 5 Sep 8 11:18 alma.sh -> ls.sh
..
-rwxr-xr-x 1 gvamosi gvamosi 25 Sep 8 11:10 ls.sh
..
drwxr-xr-x 2 gvamosi gvamosi 4096 Aug 26 2017 Videos
[{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 19359
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19359, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn({mask=[]}) = 19359
read(10, "", 8192) = 0
exit_group(0) = ?
+++ exited with 0 +++

Használjuk csak valamire ezt a kimenetet! Látható, hogy az ls parancsot a keresési útvonalban két helyen is “hiába” keresi a programunk. Nézzük meg a which paranccsal, hogy hol található az ls parancs.

gvamosi@gergo1:~$ which ls
/bin/ls

Javítsuk ki a scriptben a dolgot, írjuk bele a teljes útvonalat! Most nézzük csak meg a releváns strace kimeneti részt!

rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f52fb075840}, NULL, 8) = 0
read(10, "#!/bin/sh\n\n/bin/ls --color -l\n", 8192) = 30
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f52fb200850) = 13884
wait4(-1, total 300

Nincs is stat hívás az ls-re. Optimalizáltuk a kódot; három rendszerhívással kevesebb. Voila! 🙂

Végezetül köszönettel tartozom JÁ barátomnak a bináris debug-ért, hogy egyszer régen megtanított rá, illetve ide idézem FCs barátom jó tanácsát programozóknak, szintén köszönettel: “Programozni jól, és hibátlanul kell!” 🙂

Fork-bomba (és harakiri) :)

Ma az alábbi scriptről lesz szó, ami nemes egyszerűséggel a fork_bomb.sh nevet kapta. Arra való, hogy padlóra vigye a Linux vagy UNIX rendszert. Ha egy szülő folyamat egy gyermek folyamatot indít, fork történik. Ez a “bomba” saját magát indítja el újra meg újra. Ez egyébként csúnya dolog ebben a formában. 🙂

gvamosi@gergo1:~$ cat fork_bomb.sh
#!/bin/sh
#
# fork test by gvamosi on 2019-09-29
############################################

var1=0
if [ -n "$1" ]; then
var1=$1
fi
echo "$0 $var1"
var1=$((var1 + 1))

while true; do
sleep 2
/bin/sh $0 $var1 & # itt történik a rekurzív hívás, a "fork"
done

Hogy hogyan lehet elindítani?

gvamosi@gergo1:~$ ./fork_bomb.sh &

És leállítani, ha még nem késő? Két másodpercre vettem a sleep-jét, hogy legyen idő beavatkozni. A Linux-unk ugyan korlátozza az egy felhasználó által nyitható processzek számát, de egy másodperces sleep-pel a notebook-omat sikerült úgy megfektetnem, hogy csak a “szentháromság” (ctrl+alt+del) segített. Ugyanis hiába zárja be az operációs rendszer a processzeket, a rekurzív fork miatt újra és újra nyílnak a kis programocskák, így egy tartós leterhelt állapot keletkezik. Ilyenkor nem, vagy csak alig reagál a számítógépünk.

gvamosi@gergo1:~$ killall fork_bomb.sh
gvamosi@gergo1:~$ killall sh

Ez a két parancs segíthet, ebben a sorrendben, ha elég gyorsak vagyunk. 🙂

Utólag nézem, hogy a “kill -9 -1” – ilyet azért root-ként (rendszergazdaként) vagy dba-ként (adatbázis-adminisztrátorként) be ne írjunk, adatvesztés történhet! – úgy kivágta a saját processz-erdőmet egy szemvillanás alatt, hogy öröm volt nézni. 🙂 Megteszi reboot helyett, még jó, hogy a chrome böngészőmben van “restore” funkció a tabfülekre. 🙂

Egyébként a rendelkezésre álló “javakról” az ulimit parancs segítségével tájékozódhatunk.

gvamosi@gergo1:~$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 30575
max locked memory (kbytes, -l) 65536
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 30575
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

Jól látható, hogy 1024-nél több fork_bomb.sh-t nem igen indíthatunk. A rendszergazda így simán tökön tud rúgni minket, ha garázdálkodunk. Régebben egyébként használtak az adminok ún. “watchdog” démont, ami automtikusan reboot-olta a rendszert, ha nagy volt a baj. 🙂

Van még egy érdekes parancs. Ez a root-ként (rendszergazdaként) kiadott “rm -rf /“. Rákérdezés nélküli rekurzív törlés a gyökérből kiindulva. Használata szigorúan TILOS!!! Letöröl MINDENT a DISZKRŐL!!! VÉGLEGESEN!!! Ezt a parancsot csak egyszer adhatjuk ki. 😦

Mentés (backup)

A mentés a nagyon fontos gyakorlati rendszergazdai teendő. Az informatika egyik alaptétele a következő: ha egy adat csak egy helyen van meg, az nincsen (!).

Ezért fontos mentési stratégiát kialakítani egy szerver, de akár a desktop gépünk, illetve hordozható eszközünk esetében is! Tiszteljük meg annyira saját magunkat, hogy saját munkáinkat, adatainkat, leveleinket, kapcsolatainkat, etc. legalább lementjük egy fizikailag különböző helyre időközönként! Erre szolgál egyébként a felhő is. Azonban nem minden esetben kifizetődő a használata! Egyébként pl. az ownCloud felhőt mi is telepíthetjük. Lehet saját felhőnk is!

https://owncloud.org/

Nézzük azonban a klasszikus backup-ot, mondjuk egy kódolt hálózatit.

A szeptember 16-ai írásomban az SSH-ról leírtam a publikus kulccsal hitelesített jelszó nélküli kapcsolatot. Ez tökéletes alap egy hálózati mentéshez. Hirtelen két stratégia is eszembe jut.

  1. A távoli szerveren fut egy ún. cron job, a felhasználói crontab-ban – ez egy ütemezett feladatot jelent – mondjuk naponta. Egy script. ami ún. .tar.gz vagy .tgz tömörített állományt (archívumot) hoz létre – ez a Linux/UNIX rendszerek saját ZIP megoldása – a menteni kívánt könyvtárból, természetesen rekurzívan. Futhat pl. hajnai 3-kor. Hajnali fél négykor pedig a helyi gépünkön, ahova mentünk, lefut egy másik script, ami scp-vel, jelszó nélküli átvitelben átmásolja, “letölti” a tömörített állományt. 🙂
  2. A második megoldásban az “ssh” parancs segítségével a távoli gépen – amiről a mentést készítjük – egy scriptet futtatunk, amiben tömörítjük a menteni kívánt könyvtárat a “tar czvf <archívum_időbélyeg.tgz> <könyvtár>” paranccsal vagy a tar és a gzip parancsok kombinációjával (tar cvo <könyvtár> | gzip – > <archívum_időbélyeg.tar.gz>), ezt követően pedig scp-vel átmásoljuk a helyi gépünkre. Ezt elég lesz helyileg ütemeznünk, de akár kézzel is indíthatjuk. 🙂

https://www.shellhacks.com/ssh-execute-remote-command-script-linux/

Látható, hogy nem ördöngősség a mentés. Jóllehet azért nagyon nagy mennyiségű adat mentésénél már több eszközre van szükségünk, mint egy-két Linux parancs. 🙂

Meg kell említsem még a bzip2-t, mint egy újabb, és hatékonyabb tömörítő algoritmust használó tömörítő programcsomagot (https://www.sourceware.org/bzip2/). Általában igaz, hogy a tar archivál, a gzip és a bzip2 pedig tömörítenek. Ma már a bzip2 is alapból telepítve van egy Linux-on, sőt tar-ból is elérhető a “-j, –bzip2” kapcsolóval. Az alábbi linken található még néhány hasznos információ az archiválásról.

https://www.thomas-krenn.com/en/wiki/Archive_under_Linux_(tar,_gz,_bz2,_zip)

A log-olás (logging), naplózás alapjai

Linux rendszerünkben – pláne ha szerver – sokféle esmény történik. Ezek nyomot is hagynak – már ha jól van minden beállítva -, alapvető helyük az ún. syslog (rendszer napló), helye a könyvtárstruktúrában “/var/log/syslog“.

Beszélnünk kell még egy alapvető dologról. Minden folyamatnak van egy bemenete (STDIN, száma 0) és két kimenete: a standard kimenet (STDOUT, száma 1) és a standard hibakimenet (STDERR, száma 2).

Nézzük meg, hogyan lehet egy folyamat mindkét kimenetét “log-olni”! 🙂

root@gergo1:~# ls -lR / &> logfile

Ez aztán létrehoz nálam egy cirka 70 MByte-os logfile-t. Benne a “sima” kimenet, és a hibák is. Lássunk erre példát!

root@gergo1:~# grep "proc" logfile | less
..
/proc/11/fd:
/proc/11/fdinfo:
/proc/11/map_files:
/proc/11/net:
/proc/11/net/dev_snmp6:
/proc/11/net/netfilter:
/proc/11/net/stat:
/proc/11/ns:
/proc/11/task:
/proc/11/task/11:
ls: cannot read symbolic link '/proc/11/task/11/exe': No such file or directory
..

Látható a kimenet, és egy hiba is. Az előbbivel ekvivalens a “klasszikus” formájú parancs.

root@gergo1:~# ls -lR / > logfile.1 2>&1

Látható, hogy az STDERR “file” bele van “irányítva” az STDOUT “file”-ba, és mindkettő a “logfile.1”-be.

Vigyázat! A szimpla “kacsacsőr“, a “>” jel lenullázza a kimeneti file-t. Ha csak hozzáírni akarunk egy logfile-hoz, akkor a “dupla kacsacsőrt” kell használnuk: “>>“. Ez a “hozzáfűzés” (append).

Természetesen minden szerverfolyamatnak van log-ja, így pl. a webszerver logfile-jait a “/var/log/apache2” könyvtár alatt találjuk meg.

root@gergo1:~# l /var/log/apache2/
total 116
-rw-r—– 1 root adm 0 Sep 24 00:00 access.log
-rw-r—– 1 root adm 148 Sep 23 22:49 access.log.1
..
-rw-r—– 1 root adm 309 Sep 22 13:10 access.log.2.gz
..
-rw-r—– 1 root adm 239 Sep 24 00:00 error.log
-rw-r—– 1 root adm 869 Sep 24 00:00 error.log.1
..
-rw-r—– 1 root adm 337 Sep 23 00:46 error.log.2.gz
-rw-r—– 1 root adm 337 Sep 22 00:00 error.log.3.gz
..

Látható, hogy a régebbi logok egy számot kapnak, majd tömörítve vannak gzip-pel (a .gz kiterjesztés erre utal), naponta új logfile készül. Van “hozzáférési napló” (access log), illetve “hibanapló” (error log).

Egy logfile-t a “tail -f” paranccsal tudunk úgy megnyitni, hogy folyton lássuk az újabb sorokat, lévén ez is szövegfile. Semmi extra! 🙂

És végezetül szeretném megjegyezni, hogy leht log-olni akár egy terminálra is. Régebben a “/dev/tty12“-re, az utolsó terminálra írtam az összefoglaló logot, hogy egy egyszerű terminál-váltással (ctrl+alt+f12) azonnal láthassam, hol van valami “hiba” a szerveren. 🙂

Környezeti változók Linux alatt

Beállítani egy környezeti változót az export paranccsal lehet.

gvamosi@gergo1:~$ export KERESS_PENZT_LINUXSZAL=gvamosi.worpress.com

Kiírni egy környezeti változó értékét pedig mi sem egyszerűbb.

gvamosi@gergo1:~$ printenv KERESS_PENZT_LINUXSZAL
gvamosi.worpress.com
gvamosi@gergo1:~$ echo $KERESS_PENZT_LINUXSZAL
gvamosi.worpress.com

Az összes környezeti változót a set, env vagy printenv paranccsal kérdezhetjük le.

gvamosi@gergo1:~$ printenv | sort
COLORTERM=truecolor
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
DESKTOP_SESSION=gnome
DISPLAY=:0
GDM_LANG=en_US.UTF-8
GDMSESSION=gnome
GJS_DEBUG_OUTPUT=stderr
GJS_DEBUG_TOPICS=JS ERROR;JS LOG
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/12b6ca2c_41b1_4c0d_81ab_573afc40b82a
GNOME_TERMINAL_SERVICE=:1.91
GTK_MODULES=gail:atk-bridge
HOME=/home/gvamosi
KERESS_PENZT_LINUXSZAL=gvamosi.worpress.com
LANG=en_US.UTF-8
LOGNAME=gvamosi
OLDPWD=/home/gvamosi/Documents/irasok/Andreas_Witt-Egy_kidobott_ferfi_elete-20190418-Nagycsutortok
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:.
PWD=/home/gvamosi
QT_ACCESSIBILITY=1
QT_IM_MODULE=ibus
SESSION_MANAGER=local/gergo1:@/tmp/.ICE-unix/1075,unix/gergo1:/tmp/.ICE-unix/1075
SHELL=/bin/bash
SHLVL=0
SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
TERM=xterm-256color
USER=gvamosi
USERNAME=gvamosi
_=/usr/bin/printenv
VTE_VERSION=5402
WAYLAND_DISPLAY=wayland-0
XDG_CURRENT_DESKTOP=GNOME
XDG_MENU_PREFIX=gnome-
XDG_RUNTIME_DIR=/run/user/1000
XDG_SEAT=seat0
XDG_SESSION_CLASS=user
XDG_SESSION_DESKTOP=gnome
XDG_SESSION_ID=2
XDG_SESSION_TYPE=wayland
XDG_VTNR=2
XMODIFIERS=@im=ibus

Egy környezeti változót az unset paranccsal “törölhetünk”.

Magyarázat néhány környezeti változóhoz:

USER: az aktuáisan bejelentkezett felhasználó
HOME: a bejelentkezett felhasználó home könyvtára
SHELL: az aktuális felhasználó shell-je
LOGNAME: az aktuális felhasználó neve
PATH: a keresési útvonal parancsok végrehajtásakor (TAB billentyű)
LANG: az aktuális nyelvi beállítás
TERM: az aktuális terminálemuláció

Bővebben az alábbi weboldalon lehet a környezeti változókról olvasni.

https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/

Boole-algebra és shell script

Az és, a vagy és a negáció műveletei igen fontosak. Nézzünk egy egyszerű példát.

[ "$#" -ne 2 ] && { echo "Nem megfelelő argumentumszám"; exit; }

Hogy ez hogyan működik egy képzeletbeli script elején? Az && és kapcsolatot fejez ki. Tehát ha nem 2 argumentumot kap a script, akkor kíír egy üzenetet és kilép a programocskból. 🙂 Hogyan lehet ezt megfordítani?

[ "$#" -eq 2 ] || { echo "Nem megfelelő argumentumszám"; exit; }

Az eredmény ugyanaz. A || vagy kapcsolatot fejez ki. Vagy egyenlő 2-vel az argumentum szám, vagy kilép a programból. Az első script részlet algebrailag (A != B) és (igaz), a második (A == B) vagy (igaz).

Az egyik legfontosabb szabály, hogy a nem-és felcserélhető igen-vagy-ra. 🙂

További részletek a Boole-algebráról az alábbi linkeken.

https://hu.wikipedia.org/wiki/Boole-algebra_(informatika)

https://hu.wikipedia.org/wiki/Boole-algebra

Sorvége jel Linux, Mac és Windows alatt, folyamat kezelés parancssorból

Az ún. szövegfile-ok feldolgozása soronként történik. A sorvége karakterek a CR – carriage return, escape szekvenciája \r, (decimális kódja 13, hexadecimálisan pedig 0D, jelölik még ^M, azaz CTRL+M-ként is, “CTRL+V CTRL+M”-ként lehet “előhozni”), illetve az LF – line feed, azaz shell scriptben vagy c-ben jelölve \n (decimális kódja 10, hexadecimálisan pedig 0A).

Linux alatt – illetve OS X alatt is – ez “\n”, klasszikus Mac alatt “\r”, Windows alatt pedig “\r\n”. Látható tehát, hogy teljes káosz. 🙂

https://en.wikipedia.org/wiki/Newline

Nézzünk meg néhány hasznos billentyűzet kódot Linux/UNIX alatt, illetve a folyamat kezelés ide vonatkozó részeit!

CTRL+C: SIGINT, megszakítás, azaz interrupt, vagyis “kill
CTRL+Z
: SIGTSTP, az előtérben futó processz megszakítása, szoktak utána “bg <ENTER>“-t beírni, így a processz háttérben (background) tovább fut, jobs parancs-csal lehet kiírni a futó processzeket, illetve fg (foreground) paranccsal újra “előtérbe hozni” – eleve “háttérben” a sor végi “&” jellel lehet indítani egy folyamatot/processzt
CTRL+D: file vége, úgyis mint exit parancs a shellben, pl. bash-ban

CTRL+L: képernyőtörlés – ugyanaz, mint a “clear” parancs
CTRL+S
: leállítja a képernyőre/terminálba küldött “kimenetet”
CTRL+Q: a CTRL+S-sel leállított kimenetet “folytatja”

https://www.howtogeek.com/howto/ubuntu/keyboard-shortcuts-for-bash-command-shell-for-ubuntu-debian-suse-redhat-linux-etc/

https://www.thegeekdiary.com/understanding-the-job-control-commands-in-linux-bg-fg-and-ctrlz/

Linux parancsok II. – és a pipeline

Linux illetve UNIX-ok alatt van egy nagyon izgalmas eszköz a fejlesztő vagy rendszergazda kezében. Ez a “|” pipe jel. 🙂

https://www.guru99.com/linux-pipe-grep.html

A “|” pipe jel segítségével az egyik parancs kimenetét a következő parancs bemenetére köthetjük, így létrehozva egy pipeline-t, azaz egy csővezetéket. Értsd: egy parancs STDOUT-ját a következő parancs STDIN-jére lehet kötni. Természetesen több tagon keresztül lehet “vezetni” az adatfolyamot.

Nézzük meg a Linux/UNIX világ két legkedveltebb pager-ét, a more-t és a less-t.

gvamosi@gergo1:~$ ls -lR / | more

gvamosi@gergo1:~$ ls -lR / | less

A közös bennük, hogy az ls -lR miatt várhatóan jó hosszú listába engednek betekintést nyújtani, hiszen erre vannak kitalálva. A more csak előre “lép”, és minden UNIX rendszeren telepítve van, a less oda-vissza hagyja magát scrollozni, és implementációfüggő. 🙂

Bonyolítsuk meg a grep, azaz az egrep (reguláris kifejezések megengedettek, leírása később) funkcióval, és a hiba STDERR kimenetet irányítsuk át a null device-ba, azaz a “semmibe”.

gvamosi@gergo1:~$ ls -lR / 2> /dev/null | egrep "/home/gvamosi:$"
/home/gvamosi:

Ez a parancs egyszer ki fogja írni a “/home/gvamosi:” sztringet, mivel a gvamosi felhasználó által bebarangolható könyvtárak és fájlok között a saját home könyvtára egyszer szerepel. A grep parancs egyébként sor szinten keres szövegben adott mintát (szöveg vagy reguláris kifejezés). 🙂

Hogy miért írok a parancssori csővezetékről, azaz a pipeline-ról? A válasz abban rejlik, hogy ez mindenhol visszaköszön az infotudományban. Akár a TCP/IP adatátviteli protokoll stack, tehát az internetet felépítő protokollstruktúra – hiszen tekinthetjük a hálózatot csővezetéknek, akár egy modern és friss terminológia, a “Pipeline as Code” Jenkins alatt. 🙂

https://hu.wikipedia.org/wiki/TCP/IP

https://jenkins.io/doc/book/pipeline-as-code/

Manual pages, man pages, man lapok, használati útmutatók – rendszergazdáknak és programozóknak

Hogyan kaphatunk a parancsokról még több leírást, a --help opción felül? Erre valók az ún. manual pages, man pages – azaz a man lapok vagyis a használati útmutatók.

gvamosi@gergo1:~$ man ls

A fenti paranccsal az ls parancs használati útmutatóját, man lapjait kérhetjük le.

A man lapok szekciókba vannak sorolva. Pl. a 3-as szekcióból így kérhetjük le a printf c függvényt.

gvamosi@gergo1:~$ man 3 printf

Ezzel a lekérdezéssel máris a Linux Programmer’s Manual-ban, vagyis a Linux Programozók Kézikönyvében vagyunk. Egy kizárólagosan ebben a kézikönyvben meglévő c függvényt, pl. a getc-t, simán a man getc paranccsal is lekérdezhetjük.

gvamosi@gergo1:~$ man printf

Ez a parancs eközben a printf-et mint Linux parancsot adja vissza. Ezzel egyenértékű a

gvamosi@gergo1:~$ man 1 printf

parancs, ami alapértelmezett a printf esetében, mivel benne van az egyes szekcióban, azaz a User Commands – Felhasználói Parancsok között is. 🙂