Menu
ΠΡΟΗΓ. ΚΕΦ.   ΕΠΟΜΕΝΟ ΚΕΦ.
Menu and Table of Contents


Διεργασίες, ανακατεύθυνση, διασωλήνωση, φίλτρα

Διεργασίες

Διεργασία Εργασία Task Task Manager Process

Μια διεργασία (process) είναι ένα στιγμιότυπο ενός προγράμματος που βρίσκεται σε εκτέλεση. Κάθε διεργασία έχει τον δικό της «χώρο» μνήμης (memory space). Με απλά λόγια, όταν μια διεργασία προσπαθεί να διαβάσει το περιεχόμενο της θέσης μνήμης 10, εννοείται ότι θα διαβάσει τη θέση μνήμης 10 από τη μνήμη που έχει εκχωρηθεί στη συγκεκριμένη διεργασία και όχι την απόλυτη διεύθυνση μνήμης 10 του υπολογιστή.

Πολλές φορές αντί του όρου διεργασία χρησιμοποιείται και ο όρος εργασία (task). Για παράδειγμα, ο “Task Manager” («Διαχειριστής Εργασιών») του λειτουργικού συστήματος των Microsoft Windows μας δείχνει τις ενεργές διεργασίες. Επίσης, υπάρχει ο όρος “multi-tasking” Λειτουργικό Σύστημα. Όμως, ο όρος εργασία (task) φαίνεται πως τείνει πλέον να εγκαταλειφθεί και χρησιμοποιείται ο όρος διεργασία (process).

Μια από τις κύριες αρμοδιότητες του Λειτουργικού Συστήματος είναι η διαχείριση των διεργασιών [ , , ]. Το Λειτουργικό Σύστημα δημιουργεί, «καταστρέφει», και συγχρονίζει τις διεργασίες. Για παράδειγμα, όταν ο χρήστης πληκτρολογεί μια εντολή (πχ την ls) στο κέλυφος, τότε το κέλυφος δίνει την οδηγία στον πυρήνα να δημιουργήσει μια νέα διεργασία από το εκτελέσιμο αρχείο "ls". Ο πυρήνας θα κάνει τις απαραίτητες ενέργειες, ώστε να δημιουργηθεί η νέα διεργασία.

Μια διεργασία, αφού έχει δημιουργηθεί, μπορεί να βρίσκεται σε διάφορες καταστάσεις. Η προφανής κατάσταση είναι αυτή κατά την οποία βρίσκεται σε εκτέλεση. Ωστόσο, δεν είναι η μοναδική. Μια διεργασία μπορεί να βρίσκεται σε κατάσταση αναμονής, για να διαβάσει κάτι από το δίκτυο. Κατά τη διάρκεια του χρόνου αναμονής θα ήταν σπατάλη πόρων αυτή η διεργασία να απασχολεί την Κεντρική Μονάδα Επεξεργασίας (ΚΜΕ). Έτσι μπαίνει σε κατάσταση “blocked”, ώστε να μην απασχολήσει την ΚΜΕ, μέχρι να λάβει την απάντηση που περιμένει από το δίκτυο, άρα θα μπορεί να συνεχίσει την εκτέλεσή της.

Στα περισσότερα λειτουργικά συστήματα έχουμε τις εξής καταστάσεις όπως φαίνονται στο : Swap

Τυπικές Καταστάσεις Διεργασιών

Process PID PPID CWD ENV CMD Status Priority Ο πυρήνας διατηρεί στη μνήμη του μια λίστα με όλες τις διεργασίες, τις οποίες και χειρίζεται. Για κάθε διεργασία ο πυρήνας διατηρεί ένα σύνολο πληροφοριών:

ps (εντολή)

Η εντολή ps

H εντολή ps [] χρησιμοποιείται για να δει ο χρήστης τις διεργασίες που εκτελούνται ή για να δει πληροφορίες γι’ αυτές.

Η σύνταξη της εντολής ps είναι ως εξής:

ps [options]

Κατά τη χρήση της εντολής χρειάζεται ιδιαίτερη προσοχή στη σύνταξη των ορισμάτων, διότι κάποιες σημαίες απαιτούν την ύπαρξη της παύλας (-), ενώ κάποιες άλλες όχι. Ακολουθούν ορισμένα παραδείγματα χρήσης της εντολής με συνήθη ορίσματα, αλλά για τις πλήρης δυνατότητες της εντολής θα πρέπει να ανατρέξετε στο εγχειρίδιο χρήσης της εντολής. Επίσης, πρέπει να αναφερθεί ότι υπάρχουν πολλές παραλλαγές της εντολής (σε διάφορες παραλλαγές του UNIX) οι οποίες δεν είναι συμβατές μεταξύ τους. Ακόμη μπορεί να υπάρχουν διαφορές σε διαφορετικές εκδόσεις για το ίδιο λειτουργικό. Συνεπώς θα πρέπει να γίνεται προσεκτικά η χρήση της και συμβουλευόμενοι πάντα το εγχειρίδιο χρήσης.

asidirop@aetos:~$ ps uxww
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
asidirop  4041  0.0  0.0  11116  1172 ?        SNs  20:15   0:00 /bin/sh -c (cd /home/staff/ektaktoi/asidirop/public_html/rss_notifier/bin;./r2e run)
asidirop  4046  0.0  0.0  11116   632 ?        SN   20:15   0:00 /bin/sh -c (cd /home/staff/ektaktoi/asidirop/public_html/rss_notifier/bin;./r2e run)
asidirop  4049  0.0  0.0  11124  1348 ?        SN   20:15   0:00 /bin/sh ./r2e run
asidirop  4057 42.0  0.4 134488 22488 ?        SNl  20:15   2:28 python rss2email.py feeds.dat run
asidirop  7160  0.0  0.0  16872  1144 pts/0    RN+  20:20   0:00 ps uxww
asidirop 31887  0.0  0.0  97344  1648 ?        SN   18:44   0:00 sshd: asidirop@pts/0
asidirop 31892  0.0  0.0  19840  2120 pts/0    SNs  18:44   0:00 -bash

Στο παραπάνω παράδειγμα χρησιμοποιούνται οι σημαίες u, x και δυο φορές το w. To ww θα εμφανίσει ολόκληρη την εντολή και τα ορίσματά της. Αν χρησιμοποιούνταν ένα μόνο w, τότε θα εμφανίζονταν από ολόκληρη την εντολή μόνο όσα χωράνε στο τερματικό χωρίς να χρησιμοποιηθεί δεύτερη γραμμή. Το x εμφανίζει όλες τις διεργασίες του τρέχοντος χρήστη και τέλος το u δηλώνει τη μορφοποίηση του αποτελέσματος.

asidirop@aetos:~$ ps lxww
F   UID   PID  PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4  1143  4041  4034  25   5  11116  1172 -      SNs  ?          0:00 /bin/sh -c (cd /home/staff/ektaktoi/asidirop/public_html/rss_notifier/bin;./r2e run)
1  1143  4046  4041  25   5  11116   632 -      SN   ?          0:00 /bin/sh -c (cd /home/staff/ektaktoi/asidirop/public_html/rss_notifier/bin;./r2e run)
0  1143  4049  4046  25   5  11124  1348 -      SN   ?          0:00 /bin/sh ./r2e run
0  1143  4057  4049  25   5 134488 22488 -      SNl  ?          3:39 python rss2email.py feeds.dat run
0  1143  8967 31892  25   5   8456   744 -      RN+  pts/0      0:00 ps lxww
5  1143 31887 31832  25   5  97344  1648 ?      SN   ?          0:00 sshd: asidirop@pts/0
0  1143 31892 31887  25   5  19840  2120 -      SNs  pts/0      0:00 -bash

Στο παραπάνω παράδειγμα χρησιμοποιούνται οι ίδιες σημαίες με την προηγούμενη περίπτωση εκτός από το l που αντικαθιστά το u. Το αποτέλεσμα είναι το ίδιο, αλλά διαφέρει ως προς τις στήλες που χρησιμοποιούνται στην εκτύπωση.

asidirop@aetos:~$ ps uw -e
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   8404   160 ?        Ss   Apr03   0:43 init [2]
root         2  0.0  0.0      0     0 ?        S    Apr03   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    Apr03   0:26 [ksoftirqd/0]
root         6  0.0  0.0      0     0 ?        S    Apr03   0:05 [migration/0]
root         7  0.0  0.0      0     0 ?        S    Apr03   0:02 [watchdog/0]
root         8  0.0  0.0      0     0 ?        S    Apr03   0:05 [migration/1]
root        10  0.0  0.0      0     0 ?        S    Apr03   0:21 [ksoftirqd/1]
root        12  0.0  0.0      0     0 ?        S    Apr03   0:01 [watchdog/1]
root        13  0.0  0.0      0     0 ?        S    Apr03   0:04 [migration/2]
......................
root     31832  0.0  0.0  97344  3876 ?        SNs  18:44   0:00 sshd: asidirop [priv]
asidirop 31887  0.0  0.0  97344  1648 ?        SN   18:44   0:00 sshd: asidirop@pts/0
asidirop 31892  0.0  0.0  19840  2120 pts/0    SNs  18:44   0:00 -bash
psarnik  31944  0.0  0.0  19600  1652 ?        S    20:11   0:00 imap [psarnik ::ffff:79.103.211.1]
www-data 32457  0.0  0.1 320604  7440 ?        Sl   19:45   0:01 /usr/sbin/apache2 -k start
www-data 32488  0.0  0.1 320496  7308 ?        Sl   19:45   0:01 /usr/sbin/apache2 -k start
www-data 32489  0.1  0.1 386072  7416 ?        Sl   19:45   0:02 /usr/sbin/apache2 -k start
psarnik  32723  0.0  0.0  19680  1724 ?        S    20:12   0:00 imap [psarnik ::ffff:79.103.211.1]

To w θα εμφανίσει σχεδόν ολόκληρη την εντολή και τα ορίσματά της (όσα χωράνε στο τερματικό). Το -e εμφανίζει όλες τις διεργασίες όλων των χρηστών και τέλος το u δηλώνει τη μορφοποίηση του αποτελέσματος. pstree (εντολή)

Η εντολή pstree

Η pstree είναι αντίστοιχη εντολή με την ps, μόνο που εμφανίζει τις διεργασίες σε μορφή δέντρου με βάση τη σχέση γονέα-τέκνου. Όπως είναι εμφανές στο παρακάτω παράδειγμα, όλες οι διεργασίες έχουν ως πρόγονο την “init”. Η init είναι η βασική διεργασία που προέρχεται από τον πυρήνα και ουσιαστικά ενεργοποιεί το Λειτουργικό Σύστημα. Επίσης, δεν υπάρχει καμιά διεργασία χωρίς γονική διεργασία. όλες οι διεργασίες έχουν ως γονική τη διεργασία που τις ενεργοποίησε. Για περισσότερες πληροφορίες για την εντολή pstree ανατρέξτε στο εγχειρίδιο χρήσης.

asidirop@antonis-PC:~$ pstree
init-T-NetworkManager-T-dhclient
     ¦                L-2*[{NetworkManager}]
     +-VBoxSVC-T-VirtualBox---24*[{VirtualBox}]
     ¦         L-11*[{VBoxSVC}]
     +-VBoxXPCOMIPCD
     +-VirtualBox---5*[{VirtualBox}]
     +-acpid
     +-apache2---6*[apache2]
     +-atd
     +-avahi-daemon---avahi-daemon
     +-avgd-T-avgavid---3*[{avgavid}]
     ¦      +-avgoad-T-avgscand---6*[{avgscand}]
     ¦      ¦        L-6*[{avgoad}]
     ¦      +-avgsched---3*[{avgsched}]
     ¦      +-avgtcpd-T-avgscand---6*[{avgscand}]
     ¦      ¦         L-8*[{avgtcpd}]
     ¦      L-5*[{avgd}]
     +-bamfdaemon
     +-3*[bonobo-activati---2*[{bonobo-activat}]]
     +-chrome-T-chrome
     ¦        +-chrome---{chrome}
     ¦        +-chrome---2*[{chrome}]
     ¦        L-24*[{chrome}]
     +-chrome-T-8*[chrome---2*[{chrome}]]
     ¦        L-2*[chrome---3*[{chrome}]]
     +-2*[clock-applet---{clock-applet}]
     +-console-kit-dae---64*[{console-kit-da}]
     +-cpufreq-applet---{cpufreq-applet}
     +-cron
     +-cupsd
     +-5*[dbus-daemon]
     +-3*[dbus-launch]

Process Διεργασία

Οι Διεργασίες

Όπως έγινε φανερό από το προηγούμενο παράδειγμα, κάθε διεργασία έχει μια γονική διεργασία. Γονική διεργασία είναι η διεργασία που έδωσε «εντολή» στο Λειτουργικό Σύστημα να δημιουργηθεί η νέα. Η ταυτότητα της κάθε διεργασίας είναι το PID (Process ID) και για κάθε διεργασία υπάρχει η πληροφορία PID και PPID (Parent Process ID). Δεν υπάρχει καμία διεργασία χωρίς γονέα εκτός από τη διεργασία 0 (μηδέν). Η διεργασία 0 (μηδέν) δεν έχει γονέα και είναι η πρώτη διεργασία που εκτελείται με το boot (εκκίνηση) του συστήματος. Η διεργασία 0 αναφέρεται συνήθως και ως “swapper” ή “sched”. Είναι ο πυρήνας και δεν εμφανίζεται στη λίστα των διεργασιών.

Τι γίνεται όμως αν ο γονέας μιας διεργασίας τερματίσει πριν τερματίσουν τα τέκνα; Τα τέκνα θα έχουν ως PPID μια διεργασία που δεν υπάρχει πλέον; Προφανώς όχι. Η συμπεριφορά σε αυτήν την περίπτωση εξαρτάται από την έκδοση του Λειτουργικού Συστήματος. Συνήθης τακτική είναι να ορίζεται ως γονέας στις «ορφανές» διεργασίες η διεργασία 1, δηλαδή η init. Boot Boot Loader Init

Διαδικασία εκκίνησης συστήματος (boot)

Κατά την εκκίνηση ενός υπολογιστή:

  1. Ο boot loader, δηλαδή το πρόγραμμα που φορτώνεται από τον boot sector του δίσκου, ξεκινά τον πυρήνα (με PID 0).
  2. Ο πυρήνας ξεκινά τη διεργασία init. Αυτή, ανάλογα με τις ρυθμίσεις που είναι αποθηκευμένες θα ενεργοποιήσει όλες τις υπόλοιπες διεργασίες στο σύστημά μας.

Όταν τερματίσει η init, τότε συμβαίνει shutdown - το κλείσιμο του λειτουργικού. Fork Exec

Λειτουργίες fork και exec

Υπάρχουν δυο τρόποι, για να δημιουργηθεί μια νέα διεργασία. Ο πρώτος τρόπος είναι με τη λειτουργία fork. Όταν μια διεργασία κάνει fork (καλεί την αντίστοιχη συνάρτηση του πυρήνα), τότε δημιουργείται ένα ακριβές αντίγραφο της τρέχουσας διεργασίας. Το μόνο διαφορετικό που έχουν οι δυο διεργασίες είναι τα PID, PPID, δηλαδή οι κωδικοί διεργασιών. Έστω ότι η διεργασία Α με PID=9, PPID=3 κάνει fork και δημιουργείται μια νέα, που είναι ακριβές αντίγραφο της Α, την οποία την ονομάζουμε Β. Η Β θα έχει PPID=9 (δηλαδή ο γονέας της είναι η 9) και ως PID ένα νέο μοναδικό αριθμό (θα μπορούσε να είναι το 10). Όλα τα υπόλοιπα στοιχεία των δυο διεργασιών παραμένουν ίδια, δηλαδή ιδιοκτήτης, τρέχον κατάλογος εργασίας, μεταβλητές περιβάλλοντος, ακόμη και η πορεία εκτέλεσης.

Ο δεύτερος τρόπος είναι με τη διαδικασία exec. Όταν μια διεργασία κάνει exec με όρισμα ένα εκτελέσιμο πρόγραμμα (καλεί την αντίστοιχη συνάρτηση του πυρήνα), τότε δημιουργείται μια νέα διεργασία που τρέχει το εκτελέσιμο. Η νέα διεργασία κληρονομεί τα πάντα από τη γονική της, ακόμη και τα PID, PPID. Η παλιά διεργασία καταστρέφεται, και ουσιαστικά αντικαθίσταται από τη νέα.

Συνήθως οι λειτουργίες fork/exec εκτελούνται σε συνδυασμό. Για παράδειγμα, έστω ότι σε ένα κέλυφος έχει πληκτρολογήσει ο χρήστης την εντολή ls. Το κέλυφος, αφού ερμηνεύσει την εντολή, κάνει fork τον εαυτό του. Η γονική διεργασία του κελύφους απλά περιμένει τη θυγατρική να τερματίσει. Η θυγατρική διεργασία του κελύφους κάνει “exec /bin/ls”, οπότε και τελικά εκτελείται η εντολή ls. H ls θα έχει ως PPID το PID του γονικού κελύφους. Με τον ίδιο τρόπο ένα πρόγραμμα-διεργασία μπορεί να εκτελέσει κάποιο άλλο πρόγραμμα. Στο aaa φαίνεται η διαδικασία εκτέλεσης της εντολής “whoami” από το κέλυφος. Κάντε κλικ στο κουμπί “1. whoami”, για να ξεκινήσει η προβολή. Σε κάθε βήμα θα πρέπει να πατάτε «Επόμενο».

Η διαδικασία εκτέλεσης εντολών από το κέλυφος.
Σήμα Signal

Σήματα (signals)

Ένα σήμα είναι μια μέθοδος για επικοινωνία με μια διεργασία. Σήματα χρησιμοποιούνται στα συστήματα Unix και σε όλα τα λειτουργικά που ακολουθούν το πρότυπο POSIX. Ένα σήμα είναι μια ασύγχρονη ενημέρωση της διεργασίας ότι συνέβη ένα γεγονός (event). Όταν φτάνει ένα σήμα για μια διεργασία, ο πυρήνας διακόπτει την κανονική εκτέλεση της διεργασίας και εκτελείται ο αντίστοιχος signal handler. Signal handler είναι μια συνάρτηση της διεργασίας που θα χειριστεί το συγκεκριμένο σήμα. Για κάθε σήμα ορίζονται διαφορετικοί signal handlers. Όταν ολοκληρωθεί η εκτέλεση της συνάρτησης signal handler, η διεργασία επιστρέφει στην κανονική της εκτέλεση, στο σημείο που σταμάτησε. Εάν μια διεργασία λάβει ένα σήμα για το οποίο δεν έχει οριστεί signal handler, τότε εκτελείται ο προκαθορισμένος από το Λειτουργικό Σύστημα.

Κάθε σήμα, αναπαρίσταται με κάποιον αριθμό. Η αρίθμηση μπορεί να διαφέρει από σύστημα σε σύστημα. Στον πίνακα φαίνεται η αντιστοιχία σημάτων και των αντίστοιχων κωδικών.

Λίστα με τα σήματα από το λειτουργικό Linux.
ΣήμαΠεριγραφήΑριθμός
στο
"Linux x86"
SIGABRTProcess aborted6
SIGALRMSignal raised by alarm14
SIGBUSBus error: "access to undefined portion of memory object"7
SIGCHLDChild process terminated, stopped (or continued*)17
SIGCONTContinue if stopped18
SIGFPEFloating point exception: "erroneous arithmetic operation"8
SIGHUPHangup1
SIGILLIllegal instruction4
SIGINTInterrupt2
SIGKILLKill (terminate immediately)9
SIGPIPEWrite to pipe with no one reading13
SIGQUITQuit and dump core3
SIGSEGVSegmentation violation11
SIGSTOPStop executing temporarily19
SIGTERMTermination (request to terminate)15
SIGTSTPTerminal stop signal20
SIGTTINBackground process attempting to read from tty ("in")21
SIGTTOUBackground process attempting to write to tty ("out")22
SIGUSR1User-defined 110
SIGUSR2User-defined 212
SIGPOLLPollable event29
SIGPROFProfiling timer expired27
SIGSYSBad syscall31
SIGTRAPTrace/breakpoint trap5
SIGURGUrgent data available on socket23
SIGVTALRMSignal raised by timer counting virtual time: "virtual timer expired"26
SIGXCPUCPU time limit exceeded24
SIGXFSZFile size limit exceeded25
kill (εντολή)

Η εντολή kill

Μπορεί ο χρήστης (ή μια διεργασία) να στείλει ένα σήμα σε μια διεργασία με την εντολή kill []. Όταν η αποστολή του σήματος γίνεται μέσα από πρόγραμμα, τότε μπορεί να γίνει με την κλήση συστήματος (system call) kill, η οποία είναι αντίστοιχη με την εντολή. Παρότι το όνομα παραπλανεί, η εντολή kill ΔΕΝ «ΣΚΟΤΩΝΕΙ» μια διεργασία, αλλά στέλνει ένα σήμα σε αυτήν.

Κάποια σήματα έχει νόημα να τα στείλει ο χρήστης σε μια διεργασία, ενώ κάποια άλλα όχι. Αυτά τα δεύτερα χρησιμοποιούνται για εσωτερικούς σκοπούς από το λειτουργικό σύστημα.

Τα περισσότερο συχνά χρησιμοποιούμενα σήματα είναι:

Κάποια σήματα μπορούν να σταλούν σε μια διεργασία και από το πληκτρολόγιο (δεδομένου ότι η διεργασία εκτελείται σε ένα τερματικό). Αυτά είναι:

Δείτε τις ασκήσεις για περισσότερα παραδείγματα. Proc Directory

Στοιχεία Διεργασιών

Ένα τυπικό σύστημα Unix/Linux δίνει πρόσβαση σε όλα τα στοιχεία που διατηρεί ο πυρήνας για κάθε διεργασία μέσα από τον κατάλογο /proc. Αυτός είναι ένας εικονικός κατάλογος, ο οποίος περιέχει εικονικούς υποκαταλόγους και εικονικά αρχεία.

asidirop@aetos:~$ ls -l /proc
total 0
dr-xr-xr-x  7 root     root                   0 Apr 26 17:11 1
dr-xr-xr-x  7 root     root                   0 Apr 26 17:11 10
dr-xr-xr-x  7 dovecot  dovecot                0 Apr 26 20:03 10359
dr-xr-xr-x  7 dovecot  dovecot                0 Apr 26 19:48 10566
dr-xr-xr-x  7 dimver   x0607                  0 Apr 26 19:48 10617
dr-xr-xr-x  7 dovecot  dovecot                0 Apr 26 19:48 10618
dr-xr-xr-x  7 dimver   x0607                  0 Apr 26 19:48 10620
dr-xr-xr-x  7 dimver   x0607                  0 Apr 26 19:49 10656
dr-xr-xr-x  7 dimver   x0607                  0 Apr 26 19:49 10682
dr-xr-xr-x  7 kourou   conit                  0 Apr 26 08:01 10717
dr-xr-xr-x  7 dovecot  dovecot                0 Apr 26 20:04 11076
dr-xr-xr-x  7 dovecot  dovecot                0 Apr 26 16:02 1122
dr-xr-xr-x  7 bind     bind                   0 Apr 26 10:58 11570
dr-xr-xr-x  7 root     root                   0 Apr 26 20:04 11669
dr-xr-xr-x  7 root     root                   0 Apr 26 13:15 1176
dr-xr-xr-x  7 root     root                   0 Apr 26 18:05 11798
dr-xr-xr-x  7 dovecot  dovecot                0 Apr 26 18:06 11866

Όπως φαίνεται στο παραπάνω παράδειγμα, μέσα στον κατάλογο /proc υπάρχουν πολλοί υποκατάλογοι με ονόματα αριθμούς. Καθένας από τους καταλόγους αυτούς αντιστοιχεί σε μια διεργασία. Το όνομα του καταλόγου είναι ο κωδικός της διεργασίας (PID) στην οποία αντιστοιχεί. Σε αυτό το σημείο να παρατηρήσουμε ότι ως μέγεθος για τον κάθε κατάλογο φαίνεται το μέγεθος μηδέν.

Σε κάθε έναν από αυτούς τους καταλόγους μπορούν να βρεθούν όλες οι πληροφορίες που διατηρεί ο πυρήνας για την αντίστοιχη διεργασία.

asidirop@aetos:~$ ls -l /proc/22967
total 0
dr-xr-xr-x 2 asidirop conit 0 Apr 26 20:19 attr
-r-------- 1 asidirop conit 0 Apr 26 20:19 auxv
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 cgroup
--w------- 1 asidirop conit 0 Apr 26 20:19 clear_refs
-r--r--r-- 1 asidirop conit 0 Apr 26 20:09 cmdline
-rw-r--r-- 1 asidirop conit 0 Apr 26 20:19 comm
-rw-r--r-- 1 asidirop conit 0 Apr 26 20:19 coredump_filter
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 cpuset
lrwxrwxrwx 1 asidirop conit 0 Apr 26 20:19 cwd -> /home/staff/ektaktoi/asidirop
-r-------- 1 asidirop conit 0 Apr 26 20:19 environ
lrwxrwxrwx 1 asidirop conit 0 Apr 26 20:19 exe -> /bin/bash
dr-x------ 2 asidirop conit 0 Apr 26 20:09 fd
dr-x------ 2 asidirop conit 0 Apr 26 20:19 fdinfo
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 io
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 limits
-rw-r--r-- 1 asidirop conit 0 Apr 26 20:19 loginuid
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 maps
-rw------- 1 asidirop conit 0 Apr 26 20:19 mem
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 mountinfo
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 mounts
-r-------- 1 asidirop conit 0 Apr 26 20:19 mountstats
dr-xr-xr-x 7 asidirop conit 0 Apr 26 20:19 net
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 numa_maps
-rw-r--r-- 1 asidirop conit 0 Apr 26 20:19 oom_adj
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 oom_score
-rw-r--r-- 1 asidirop conit 0 Apr 26 20:19 oom_score_adj
-r-------- 1 asidirop conit 0 Apr 26 20:19 pagemap
-r-------- 1 asidirop conit 0 Apr 26 20:19 personality
lrwxrwxrwx 1 asidirop conit 0 Apr 26 20:19 root -> /
-rw-r--r-- 1 asidirop conit 0 Apr 26 20:19 sched
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 sessionid
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 smaps
-r-------- 1 asidirop conit 0 Apr 26 20:19 stack
-r--r--r-- 1 asidirop conit 0 Apr 26 20:09 stat
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 statm
-r--r--r-- 1 asidirop conit 0 Apr 26 20:09 status
-r-------- 1 asidirop conit 0 Apr 26 20:19 syscall
dr-xr-xr-x 3 asidirop conit 0 Apr 26 20:19 task
-r--r--r-- 1 asidirop conit 0 Apr 26 20:19 wchan

Παραπάνω βλέπουμε ότι υπάρχουν 38 αρχεία που περιέχουν διάφορες πληροφορίες για κάθε διεργασία. Και πάλι πρέπει να παρατηρηθεί ότι όλα αυτά τα αρχεία φαίνεται να έχουν μέγεθος μηδέν.

Ένα χρήσιμο αρχείο είναι το αρχείο stat, του οποίου τα περιεχόμενα εμφανίζονται παρακάτω για μια τυχαία διεργασία. Βλέπουμε ότι περιέχονται πληροφορίες που αφορούν την κατάσταση της διεργασίας, κωδικοί (PID, PPID, UID κ.ά.), καθώς και πληροφορίες για τη χρήση μνήμης από τη διεργασία. Η εντολή ps στην ουσία διαβάζει αυτές τις πληροφορίες και τις εμφανίζει με μορφή που ορίζεται από τα ορίσματα που δίνει ο χρήστης.

asidirop@aetos:~$ more /proc/22967/status
Name:	bash
State:	S (sleeping)
Tgid:	22967
Pid:	22967
PPid:	22963
TracerPid:	0
Uid:	1143	1143	1143	1143
Gid:	993	993	993	993
FDSize:	256
Groups:	993
VmPeak:	   19904 kB
VmSize:	   19840 kB
VmLck:	       0 kB
VmHWM:	    2096 kB
VmRSS:	    2096 kB
VmData:	     424 kB
VmStk:	     136 kB
VmExe:	     868 kB
VmLib:	    1972 kB
VmPTE:	      60 kB
VmSwap:	       0 kB
Threads:	1
SigQ:	0/16382
SigPnd:	0000000000000000
ShdPnd:	0000000000000000
SigBlk:	0000000000010000
SigIgn:	0000000000384004
SigCgt:	000000004b813efb
CapInh:	0000000000000000
CapPrm:	0000000000000000
CapEff:	0000000000000000
CapBnd:	ffffffffffffffff
Cpus_allowed:	ff
Cpus_allowed_list:	0-7
Mems_allowed:	00000000,00000001
Mems_allowed_list:	0
voluntary_ctxt_switches:	152
nonvoluntary_ctxt_switches:	1
Μεταβλητές Περιβάλλοντος Environment Variables

Οι μεταβλητές περιβάλλοντος

Για κάθε διεργασία ο πυρήνας διατηρεί έναν πίνακα με «Μεταβλητές Περιβάλλοντος» (Environment Variables). Οι μεταβλητές περιβάλλοντος δεν είναι χαρακτηριστικό μόνο των κελυφών, αλλά υπάρχουν για όλες τις διεργασίες. Μάλιστα μεταβλητές περιβάλλοντος υπάρχουν και στα Λειτουργικά Συστήματα των Microsoft Windows και όχι μόνο στις παραλλαγές του UNIX.

Οι μεταβλητές περιβάλλοντος χρησιμοποιούνται:

Όλες οι Μεταβλητές Περιβάλλοντος κληροδοτούνται από τις διεργασίες στις θυγατρικές τους. Έτσι, στην πραγματικότητα όλες οι διεργασίες κληρονομούν τις μεταβλητές περιβάλλοντος που αρχικοποιούνται από τη διεργασία init. Προφανώς η κάθε διεργασία μπορεί να τροποποιήσει τις Μεταβλητές Περιβάλλοντός της, οι οποίες βέβαια θα κληροδοτηθούν στις θυγατρικές της. env (εντολή) export (εντολή)

Μέσα από το κέλυφος ο χρήστης μπορεί να εμφανίσει τις μεταβλητές περιβάλλοντος χρησιμοποιώντας την εντολή env όπως φαίνεται παρακάτω:

asidirop@aetos:~$ env
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=94.68.138.167 55038 22
SSH_TTY=/dev/pts/0
USER=asidirop
MAILCHECK=3600
MAIL=/var/mail/asidirop
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/home/staff/ektaktoi/asidirop/bin
PWD=/home/staff/ektaktoi/asidirop
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/staff/ektaktoi/asidirop
LOGNAME=asidirop
SSH_CONNECTION=94.68.138.167 55038 195.251.123.232 22
DISPLAY=:0
_=/usr/bin/env

Μέσα από το κέλυφος Bourne Shell μπορεί ο χρήστης να τροποποιήσει τις μεταβλητές περιβάλλοντος της διεργασίας που αντιστοιχεί στο κέλυφος. Αυτό μπορεί να γίνει απλά με μια εντολή εκχώρησης όπως φαίνεται παρακάτω:

asidirop@aetos:~$ LANG=el_GR.UTF-8
asidirop@aetos:~$ env
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=94.68.138.167 55038 22
SSH_TTY=/dev/pts/0
USER=asidirop
MAILCHECK=3600
MAIL=/var/mail/asidirop
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/home/staff/ektaktoi/asidirop/bin
PWD=/home/staff/ektaktoi/asidirop
LANG=el_GR.UTF-8
SHLVL=1
HOME=/home/staff/ektaktoi/asidirop
LOGNAME=asidirop
SSH_CONNECTION=94.68.138.167 55038 195.251.123.232 22
DISPLAY=:0
_=/usr/bin/env

Εάν ο χρήστης θέλει να ορίσει μια νέα μεταβλητή περιβάλλοντος, θα πρέπει να χρησιμοποιήσει την εντολή export. Αυτό μπορεί να γίνει με δυο τρόπους. Ο πρώτος τρόπος είναι όπως παρακάτω, δηλαδή ορίζοντας αρχικά τη μεταβλητή του κελύφους TEST και μετά εκτελώντας την εντολή export. Ουσιαστικά δίνει στο κέλυφος την οδηγία να μετατρέψει την τοπική μεταβλητή TEST σε Μεταβλητή Περιβάλλοντος.

asidirop@aetos:~$ TEST=xyz
asidirop@aetos:~$ export TEST
asidirop@aetos:~$ env
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=94.68.138.167 55038 22
SSH_TTY=/dev/pts/0
USER=asidirop
MAILCHECK=3600
MAIL=/var/mail/asidirop
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/home/staff/ektaktoi/asidirop/bin
PWD=/home/staff/ektaktoi/asidirop
LANG=el_GR.UTF-8
TEST=xyz
SHLVL=1

Ο εναλλακτικός τρόπος είναι να χρησιμοποιηθεί η εντολή export στην ίδια εντολή με την εκχώρηση:

asidirop@aetos:~$ export TEST=xyz

Άλλα κελύφη εκτός του Bourne Shell παρέχουν άλλους τρόπους για τον χειρισμό των μεταβλητών περιβάλλοντος. Για παράδειγμα στα κελύφη της οικογένειας csh χρησιμοποιείται η εντολή setenv. Μέσα από προγράμματα μπορεί ο προγραμματιστής να διαβάσει ή να τροποποιήσει τις μεταβλητές περιβάλλοντος χρησιμοποιώντας συναρτήσεις που αντιστοιχούν στις κλήσεις συστήματος setenv και getenv. Εναλλακτικά, ανάλογα με τη γλώσσα προγραμματισμού μπορεί να παρέχεται και άλλος τρόπος για πρόσβαση στις μεταβλητές περιβάλλοντος, για παράδειγμα στη γλώσσα προγραμματισμού php υπάρχει ο πίνακας $_ENV τον οποίον ο προγραμματιστής μπορεί να χρησιμοποιήσει, όπως οποιονδήποτε άλλον πίνακα της γλώσσας.

Στις μεταβλητές περιβάλλοντος υπάρχει πρόσβαση και μέσω των αρχείων στο /proc. Για κάθε διεργασία υπάρχει το αρχείο environ το οποίο περιέχει τον πίνακα μεταβλητών περιβάλλοντος. Βέβαια αν προσπαθήσει ο χρήστης να δει αυτό το αρχείο με μια εντολή cat το αποτέλεσμα δεν εμφανίζεται "στοιχισμένο", παρόλα αυτά περιέχονται όλες οι πληροφορίες.

asidirop@aetos:~$ ps
  PID TTY          TIME CMD
20870 pts/0    00:00:00 bash
29411 pts/0    00:00:00 ps
asidirop@aetos:~$ cat /proc/20870/environ
LANG=en_US.UTF-8USER=asidiropLOGNAME=asidiropHOME=/home/staff/ektaktoi/asidiropPATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/gamesMAIL=/var/mail/asidiropSHELL=/bin/bashSSH_CLIENT=94.68.138.167 55038 22SSH_CONNECTION=94.68.138.167 55038 195.251.123.232 22SSH_TTY=/dev/pts/0TERM=xterm
LANG LANGUAGE Μεταβλητή Περιβάλλοντος LANG Μεταβλητή Περιβάλλοντος LANGUAGE Τοπικές Ρυθμίσεις Διεργασίας

Χρήσιμες Μεταβλητές Περιβάλλοντος

Ένα πολύ χρήσιμο σύνολο μεταβλητών περιβάλλοντος είναι οι μεταβλητές που αφορούν τη γλώσσα και τα σύμβολα εμφάνισης, πχ αν στην ώρα θα υπάρχει το π.μ. ή το a.m. Αυτές είναι οι:

Αυτές οι μεταβλητές περιβάλλοντος χρησιμοποιούνται από τις βιβλιοθήκες του συστήματος και των γλωσσών προγραμματισμού για τη σωστή εμφάνιση μηνυμάτων. Βασικές μεταβλητές είναι οι LANG και LANGUAGE. Αυτές οι δυο μεταβλητές ορίζουν τη γλώσσα επικοινωνίας των προγραμμάτων και τον χρήστη. Κάποια προγράμματα λαμβάνουν υπόψη τη μεταβλητή LANG, ενώ κάποια άλλα τη μεταβλητή LANGUAGE, γι' αυτό θα πρέπει να τίθενται και οι δυο στην ίδια τιμή. Βλέπουμε, για παράδειγμα, παρακάτω την εμφάνιση λαθών από την εντολή ls. Στη μια περίπτωση το μήνυμα λάθους εμφανίζεται στα Αγγλικά, ενώ στην άλλη στα Ελληνικά. Δεν έχουν όλα τα προγράμματα μεταφράσεις για όλες τις γλώσσες, συνεπώς πολλές φορές η μετάφραση είναι ημιτελής, όπως παρακάτω. Παρότι η ls εμφανίζει στα Ελληνικά το μήνυμα: «Δεν υπάρχει τέτοιο αρχείο ή κατάλογος», εμφανίζεται και το μήνυμα “cannot access”, για το οποίο δεν έχει οριστεί η κατάλληλη μετάφραση στην εντολή ls.

asidirop@aetos:~$ ls /dfg 
ls: cannot access /dfg: No such file or directory
asidirop@aetos:~$ export LANG=el_GR.UTF-8
asidirop@aetos:~$ ls /dfg
ls: cannot access /dfg: Δεν υπάρχει τέτοιο αρχείο ή κατάλογος
asidirop@aetos:~$
Μεταβλητή Περιβάλλοντος PATH PATH

Επόμενη ιδιαίτερα σημαντική μεταβλητή περιβάλλοντος είναι η PATH. Μέσω αυτής ορίζεται σε ποιους καταλόγους θα ψάχνει το κέλυφος για να βρει το εκτελέσιμο της εντολής που έχει πληκτρολογήσει ο χρήστης. Η μεταβλητή περιλαμβάνει διαδρομές προς καταλόγους χωρισμένες με τον χαρακτήρα ":" όπως παρακάτω:

PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/home/staff/ektaktoi/asidirop/bin

Κάθε φορά που ο χρήστης πληκτρολογεί μια εντολή (πχ ls), το κέλυφος ψάχνει με τη σειρά όλους τους καταλόγους που ορίζονται στο PATH, για να βρει το εκτελέσιμο της ls. Στην πρώτη θέση που θα το βρει, σταματά την αναζήτηση και εκτελεί την εντολή από τον κατάλογο που βρέθηκε.

Εάν ένα εκτελέσιμο δεν βρίσκεται στο PATH (δηλαδή δεν είναι αποθηκευμένο σε κατάλογο που περιλαμβάνεται στο ΡΑΤΗ), για να το εκτελέσει ο χρήστης, θα πρέπει να δώσει τη διαδρομή προς αυτό, είτε απόλυτη είτε σχετική. Παράδειγμα, παρακάτω η εντολή fsck είναι αποθηκευμένη στον κατάλογο /sbin, ο οποίος δεν βρίσκεται στο PATH. Έτσι, δεν μπορεί ο χρήστης να την εκτελέσει πληκτρολογώντας μόνο το όνομά της αλλά πρέπει να πληκτρολογήσει τη διαδρομή προς αυτήν.

asidirop@aetos:~$ fsck
-bash: fsck: command not found
asidirop@aetos:~$ /sbin/fsck
fsck from util-linux-ng 2.17.2
If you wish to check the consistency of an XFS filesystem or
repair a damaged filesystem, see xfs_check(8) and xfs_repair(8).
e2fsck 1.41.12 (17-May-2010)
File Descriptor File Handler IO Streams Redirection Ροές Εισόδου-Εξόδου Ανακατεύθυνση Κανονική Είσοδος Κανονική Έξοδος Έξοδος Λαθών Stdin Stdout Stderr

Ροές Εισόδου-Εξόδου και Ανακατεύθυνση

Η πληροφορία, ποια αρχεία έχει ανοιχτά η κάθε διεργασία, πρέπει να αποθηκεύεται κάπου. Αυτήν την πληροφορία τη διατηρεί ο πυρήνας για κάθε διεργασία, και δεδομένου ότι μια διεργασία μπορεί να έχει πολλά αρχεία ανοιχτά συγχρόνως, απαιτείται ένας πίνακας που να αποθηκεύει αυτές τις πληροφορίες. Τα στοιχεία του πίνακα στο unix αναφέρονται ως file descriptors, ενώ στα Windows αναφέρονται ως file handlers, στην πραγματικότητα όμως είναι το ίδιο.

Για κάθε ανοιχτό αρχείο διατηρούνται διάφορες πληροφορίες. Σημαντική πληροφορία είναι η θέση του «Κέρσορα» μέσα στο αρχείο. Ο Κέρσορας περιέχει την πληροφορία από ποια θέση του αρχείου να διαβαστούν δεδομένα κατά την επόμενη ανάγνωση (read) που θα κάνει η διεργασία από το αρχείο. Αν δεν υπήρχε ο Κέρσορας τότε πάντα μια διεργασία θα διάβαζε συνεχώς μόνο το πρώτο byte από ένα αρχείο. Για παράδειγμα, όταν ένα πρόγραμμα ανοίγει ένα αρχείο (πχ για ανάγνωση) ο κέρσορας είναι στη θέση 0. Εάν το πρόγραμμα διαβάσει (read) 5 bytes από το αρχείο, τότε ο κέρσορας μετακινείται 5 θέσεις. Την επόμενη φορά που θα κάνει ανάγνωση (read) το πρόγραμμα θα διαβάσει τα επόμενα bytes του αρχείου. Με αυτόν τον τρόπο βήμα-βήμα θα φτάσει κάποια στιγμή στο τέλος του αρχείου.

Βλέποντας τον φάκελο fd από το /proc μιας διεργασίας, μπορεί ο χρήστης να δει ποια αρχεία έχει ανοιχτά μια διεργασία (αρκεί να το επιτρέπουν οι άδειες πρόσβασης). Στο παρακάτω παράδειγμα βλέπουμε τα αρχεία που έχει ανοιχτά η διεργασία που αντιστοιχεί το πρόγραμμα “firefox” (στην πραγματικότητα είναι 10άδες στην περίπτωση του firefox).

asidirop@antonis-PC:~$ ls -l /proc/10569/fd
total 0
lr-x------ 1 asidirop asidirop 64 2012-04-26 19:14 0 -> /dev/null
lrwx------ 1 asidirop asidirop 64 2012-04-26 19:14 1 -> /home/asidirop/.xsession-errors
l-wx------ 1 asidirop asidirop 64 2012-04-26 19:14 10 -> pipe:[46911]
lrwx------ 1 asidirop asidirop 64 2012-04-26 19:14 101 -> socket:[3928988]
lrwx------ 1 asidirop asidirop 64 2012-04-26 19:14 102 -> socket:[637537]
lr-x------ 1 asidirop asidirop 64 2012-04-26 19:14 103 -> /home/asidirop/.mozilla/firefox/9nb3c2bh.default/places.sqlite
lrwx------ 1 asidirop asidirop 64 2012-04-26 19:14 106 -> /home/asidirop/.mozilla/firefox/9nb3c2bh.default/places.sqlite-wal
.......

Όλες οι διεργασίες έχουν εξ’ ορισμού τρεις ανοιχτές ροές εισόδου-εξόδου, ουσιαστικά τρία ανοιχτά αρχεία. Για παράδειγμα, αν φτιάξουμε ένα απλό πρόγραμμα το οποίο δεν κάνει τίποτε και το εκτελέσουμε, αν ελέγξουμε τα ανοιχτά αρχεία στον φάκελο /proc/PID/fd θα δούμε τρεις εγγραφές:

asidirop@antonis-PC:~$ ls -l /proc/13238/fd
total 0
lrwx------ 1 asidirop asidirop 64 Jul 17 15:46 0 -> /dev/pts/2
lrwx------ 1 asidirop asidirop 64 Jul 17 15:46 1 -> /dev/pts/2
lrwx------ 1 asidirop asidirop 64 Jul 17 15:46 2 -> /dev/pts/2

Αυτές οι ροές εισόδου-εξόδου είναι οι:

Αυτό ισχύει σχεδόν για όλα τα Λειτουργικά Συστήματα και προφανώς δεν εξαρτάται από τη γλώσσα προγραμματισμού με την οποία δημιουργήθηκε το εκτελέσιμο που αντιστοιχεί στη διεργασία. Σε όλες τις γλώσσες προγραμματισμού υπάρχουν μεταβλητές ή αντικείμενα που αντιστοιχούν σε αυτές τις ροές εισόδου-εξόδου. Σε κάθε γλώσσα προγραμματισμού μπορεί να αναφέρονται με διαφορετικό όνομα, αντιστοιχούν όμως στο ίδιο στοιχείο:

Στις περισσότερες γλώσσες προγραμματισμού, όταν παραλείπεται η αναφορά σε αρχείο, εννοείται η κανονική είσοδος (stdin), όταν πρόκειται για ανάγνωση, ενώ εννοείται η κανονική έξοδος (stdout), όταν πρόκειται για εγγραφή. Παράδειγμα, στη γλώσσα C τα δυο παρακάτω είναι ισοδύναμα:

	fprintf(stdout,"TEST\n");
	printf("TEST\n");

Αντίστοιχα, όταν πρόκειται για ανάγνωση τα δυο παρακάτω στη γλώσσα C είναι ισοδύναμα:

	fscanf(stdin,"%s",tmp);
	scanf("%s",tmp);

O "file descriptor" είναι ένας ακέραιος (integer) που δείχνει τη θέση του αρχείου στον πίνακα με τα ανοιχτά αρχεία της διεργασίας. Μια διεργασία έχει εξ ορισμού τρία ανοιχτά αρχεία τα οποία βρίσκονται στις θέσεις 0,1,2 του πίνακα ανοιχτών αρχείων και αντιστοιχούν στην κανονική είσοδο, κανονική έξοδο και έξοδο λαθών, όπως φαίνεται στον .

Τα προκαθορισμένα ανοιχτά αρχεία που αντιστοιχούν στις ροές εισόδου-εξόδου.
Θέση Αντιστοιχία
0 Κανονική είσοδος (stdin)
1 Κανονική έξοδος (stdout)
2 Έξοδος Λαθών (stderr)
pts

Το Λειτουργικό Σύστημα κρατάει σε κάθε θέση του πίνακα διάφορες πληροφορίες που αντιστοιχούν στο ανοιχτό αρχείο όπως τη θέση του Κέρσορα στο αρχείο, την κατάσταση ανοίγματος (read, write, append), κ.ά.

Μπορούμε να ελέγξουμε ποια αρχεία έχει ανοιχτά ένα κέλυφος καθώς εκτελείται. Στο παρακάτω παράδειγμα φαίνεται ότι το τρέχον κέλυφος έχει τρία ανοιχτά αρχεία που αντιστοιχούν σε συσκευή τερματικού (/dev/pts/1). Αυτό σημαίνει ότι το συγκεκριμένο κέλυφος γράφει και διαβάζει από το τερματικό /dev/pts/1. Άρα, αν τυπώσει κάτι στην κανονική έξοδο, θα τυπωθεί στο /dev/pts/1 και τελικά θα εμφανιστεί (υπό φυσιολογικές συνθήκες) στην οθόνη του χρήστη.

asidirop@aetos:~$ ps # Βρίσκουμε το PID του τρέχοντος κελύφους
  PID TTY          TIME CMD
 7218 pts/1    00:00:00 ps
22967 pts/1    00:00:00 bash
asidirop@aetos:~$ ls -l /proc/22967/fd
total 0
lrwx------ 1 asidirop conit 64 Apr 27 02:18 0 -> /dev/pts/1
lrwx------ 1 asidirop conit 64 Apr 27 02:18 1 -> /dev/pts/1
lrwx------ 1 asidirop conit 64 Apr 27 00:35 2 -> /dev/pts/1
Κάθε διεργασία κληρονομεί από τη γονική της τον πίνακα ανοιχτών αρχείων. Αναλυτικότερα, με τη μέθοδο exec κληρονομούνται μόνο οι τρεις πρώτες θέσεις του πίνακα, ενώ με τη μέθοδο fork κληρονομείται ολόκληρος ο πίνακας. Όταν ο χρήστης πληκτρολογεί μια εντολή στο κέλυφος, το κέλυφος πρώτα κάνει fork και μετά exec την εντολή (όπως δείξαμε στο ) , συνεπώς η νέα διεργασία που θα προκύψει θα έχει κληρονομήσει από το αρχικό κέλυφος τα stdin, stdout και stderr, όπως παρουσιάζεται στο . Παρατηρήστε ότι στο σχήμα (και σε κάθε επόμενο σχήμα) αναπαριστώνται με διαφορετικά βέλη οι ροές κανονικής εξόδου και εξόδου λαθών.
Μια διεργασία κληρονομεί από τη γονική της τις ροές εισόδου-εξόδου.

Στο εμφανίζονται τέσσερα παραδείγματα εντολών για την κατανόηση του τρόπου λειτουργίας των ροών εισόδου-εξόδου και του τερματικού. Στα δυο πρώτα για λόγους απλοποίησης δεν περιλαμβάνεται η διαδικασία του κελύφους fork-exec, ενώ περιλαμβάνεται στα δυο επόμενα. Στο παρακάτω διαδραστικό σχήμα επιλέξτε ένα από τα τέσσερα παραδείγματα (κατά προτίμηση με τη σειρά), για να δείτε τα βήματα που συμβαίνουν σε σχέση με τις ροές εισόδου-εξόδου, όταν εκτελείται μια εντολή.

Η διαδικασία δημιουργίας των ροών εισόδου-εξόδου κατά την εκτέλεση μιας εντολής.
IO Streams Redirection Ροές Εισόδου-Εξόδου Ανακατεύθυνση

Ανακατεύθυνση (Redirection)

Ο χρήστης μπορεί να δώσει διάφορες οδηγίες προς το κέλυφος, ώστε να αλλάξει τις προκαθορισμένες ροές εισόδου-εξόδου. Έτσι, χρησιμοποιώντας το σύμβολο > ορίζεται αλλαγή της κανονικής εξόδου. Μετά από το σύμβολο > πρέπει να ακολουθεί όνομα αρχείου. Έτσι, η κανονική έξοδος της εντολής θα ανακατευθυνθεί στο αρχείο που ορίστηκε. Στο παρακάτω παράδειγμα, η εντολή ls δεν θα εμφανίσει τίποτα στην οθόνη, αλλά η έξοδός της θα αποθηκευτεί στο αρχείο file1. Στο παρουσιάζονται σχηματικά οι ροές εισόδου-εξόδου του παραδείγματος.

asidirop@aetos:~$ ls -l > file1
asidirop@aetos:~$
Αλλαγή της κανονικής εξόδου προς αρχείο.

Αν, όμως, η ls εμφανίσει μήνυμα λάθους, τότε αυτό θα σταλεί στο “stderr”, άρα στην οθόνη. Κάτι τέτοιο θα ήταν το αποτέλεσμα της παρακάτω εντολής:

asidirop@aetos:~$ ls -l /foo > file1
ls: cannot access /foo: No such file or directory
asidirop@aetos:~$
OK Υπάρχει η γενική πολιτική: μέσα από ένα πρόγραμμα αν θέλουμε να τυπώσουμε ένα μήνυμα λάθους, τότε αυτό θα πρέπει να τυπωθεί στην έξοδο λαθών (stderr) και ΌΧΙ στην τυπική έξοδο (stdout). Αυτή η πολιτική πρέπει να ακολουθείται σε όλες τις περιπτώσεις και μέσα από όλες τις γλώσσες προγραμματισμού και σε όλα τα Λειτουργικά Συστήματα (unix ή windows).
Λίστα με τα σύμβολα ανακατεύθυνσης.
ΣύμβολοΠεριγραφή
>file
1> file
Άλλαξε το stdout, ώστε να «γράφει» στο αρχείο file και όχι στο προκαθορισμένο. Το file, αν υπάρχει, θα διαγραφεί, αν δεν υπάρχει θα δημιουργηθεί.
>>file
1>> file
Άλλαξε το stdout, ώστε να «γράφει» στο αρχείο file και όχι στο προκαθορισμένο. Το file, αν υπάρχει, ΔΕΝ θα διαγραφεί, αν δεν υπάρχει θα δημιουργηθεί. Τα δεδομένα από την εντολή θα γίνουν append στο file.
2> fileΆλλαξε το stderr, ώστε να «γράφει» στο αρχείο file και όχι στο προκαθορισμένο. Το file, αν υπάρχει, θα διαγραφεί, αν δεν υπάρχει θα δημιουργηθεί.
2>> fileΆλλαξε το stderr, ώστε να «γράφει» στο αρχείο file και όχι στο προκαθορισμένο. Το file, αν υπάρχει, ΔΕΝ θα διαγραφεί, αν δεν υπάρχει θα δημιουργηθεί. Τα δεδομένα από την εντολή θα γίνουν append στο file.
< fileΆλλαξε το stdin, ώστε να «διαβάζει» από το αρχείο file και όχι από το προκαθορισμένο (τερματικό). Αν δεν υπάρχει το file, τότε θα πάρουμε σφάλμα.
<< STRINGΆλλαξε, ώστε το stdin να «διαβάζει» από το κέλυφος. Το κέλυφος θα περιμένει να πληκτρολογήσουμε δεδομένα, μέχρι να πληκτρολογήσουμε τη γραμμή STRING. Τότε, ό,τι πληκτρολογήσαμε θα το στείλει στο stdin της διεργασίας.
1>&2Στείλε την έξοδο από το 1 (stdout) στο 2 (stderr). Στη γενική περίπτωση, x>&y, στείλε το x στο y.

Στον συνοψίζονται τα σύμβολα που χρησιμοποιούνται για την αλλαγή των ροών εισόδου-εξόδου. Πριν από το σύμβολο ">" μπαίνει ο αριθμός του ανοιχτού αρχείου προς ανακατεύθυνση. Αν αυτός ο αριθμός παραλείπεται, τότε εννοείται το ένα (1) το οποίο αντιστοιχεί στην κανονική έξοδο. To (2) αντιστοιχεί στην έξοδο λαθών. Έτσι, αν χρησιμοποιήσουμε το "2>", μόνο η έξοδος λαθών θα ανακατευθυνθεί σε αρχείο, όπως στο επόμενο παράδειγμα:

asidirop@aetos:~$ ls -l /foo 2> file2
asidirop@aetos:~$ cat file2
ls: cannot access /foo: No such file or directory
asidirop@aetos:~$
Αλλαγή της εξόδου λαθών προς αρχείο.

Εάν η εντολή (διεργασία) στείλει δεδομένα και στην κανονική έξοδο, αλλά και στην έξοδο λαθών, τότε το κάθε τι θα αποθηκευτεί ή θα εμφανιστεί στη ροή που του αντιστοιχεί.

asidirop@aetos:~$ ls /tmp /foo 2> file2
/tmp:
20112xeim-adopse.tar.bz2  cake       filename     myid2    t         textVi.txt
arx                       fff        leleris.txt  myid9    test      too2l
arxeio2                   file1      ls           myidnik  test01    too3l
asd                       file1.txt  mc-antant    o        test.txt
ask3erg4                  file3      mybest       otinane  testvi1
asidirop@aetos:~$ cat file2
ls: cannot access /foo: No such file or directory
asidirop@aetos:~$

Στην παραπάνω εντολή ls δόθηκε η οδηγία να εμφανίζει τα περιεχόμενα των καταλόγων /tmp και /foo. Ο /tmp υπάρχει, και η εντολή εμφανίζει τα περιεχόμενά του στην κανονική έξοδο, δηλαδή εμφανίζονται στο τερματικό. Ο /foo δεν υπάρχει, και η εντολή εμφανίζει μήνυμα λάθους, το οποίο στέλνει στην έξοδο λαθών, η οποία αντιστοιχεί στο αρχείο file2. Αν εμφανίσουμε τα περιεχόμενα του file2, είναι ξεκάθαρο ότι περιέχει το μήνυμα λάθους της ls.

Σε μια εντολή είναι δυνατό να αλλάξει ο χρήστης πολλές ροές εισόδου-εξόδου. Έτσι, παρακάτω αλλάζουν και οι δυο ροές. Η κανονική έξοδος αποθηκεύεται στο file1, ενώ η έξοδος λαθών στο file2. Σχηματική αναπαράσταση αυτής της εντολής φαίνεται στο .

asidirop@aetos:~$ ls /tmp /foo > file1 2> file2
asidirop@aetos:~$ cat file1
20112xeim-adopse.tar.bz2
arx
arxeio2
asd
ask3erg4
cake
fff
file1
file1.txt
........
asidirop@aetos:~$ cat file2
ls: cannot access /foo: No such file or directory
asidirop@aetos:~$
Αλλαγή της κανονικής εξόδου και της εξόδου λαθών προς διαφορετικά αρχεία.

Στην τελευταία γραμμή του αναφέρεται η δυνατότητα ανακατεύθυνσης μιας ροής σε μια άλλη. Με την παρακάτω εντολή ανακατευθύνεται η έξοδος λαθών στην κανονική έξοδο (). Από το αποτέλεσμα δεν είναι προφανές τι συνέβη, διότι και οι δυο ροές έτσι κι αλλιώς αντιστοιχούν στο τερματικό. Όμως αυτό που συνέβη εσωτερικά είναι να διαγραφεί η θέση 2 του πίνακα με τα ανοιχτά αρχεία και να αντικατασταθεί το περιεχόμενό της με ό,τι περιέχει η θέση 1 (κανονική έξοδος).

asidirop@aetos:~$ ls /foo 2>&1
ls: cannot access /foo: No such file or directory
asidirop@aetos:~$
Αλλαγή της εξόδου λαθών προς την κανονική έξοδο.

Στα παρακάτω παραδείγματα είναι περισσότερο εμφανές τι συμβαίνει. Ανακατευθύνεται η κανονική έξοδος στο αρχείο file1 και μετά ανακατευθύνεται η έξοδος λαθών στην κανονική έξοδο, δηλαδή στο αρχείο file1. Έτσι, στο αρχείο file1 αποθηκεύονται τα δεδομένα της κανονικής εξόδου αλλά και της εξόδου λαθών. Εδώ να σημειωθεί ότι αυτός είναι ο μόνος τρόπος να γίνει αποθήκευση δυο ροών σε ένα αρχείο. Στο φαίνεται σχηματικά η δομή των ανακατευθύνσεων.

asidirop@aetos:~$ ls /tmp /foo > file1 2>&1
asidirop@aetos:~$ cat file1
ls: cannot access /foo: No such file or directory
20112xeim-adopse.tar.bz2
arx
arxeio2
asd
ask3erg4
cake
fff
file1
file1.txt
........
Αλλαγή της κανονικής εξόδου προς αρχείο και της εξόδου λαθών προς την κανονική έξοδο.

Στην περίπτωση που γίνεται ανακατεύθυνση μιας ροής σε μια άλλη, είναι σημαντική η σειρά με την οποία ορίζονται οι ανακετευθύνσεις (ενώ σε άλλες περιπτώσεις δεν παίζει ρόλο η σειρά). Έτσι για παράδειγμα, αν γίνει πρώτα η 2>&1 και μετά το >file όπως παρακάτω:

asidirop@aetos:~$ ls /tmp /foo 1 2>&1  > file 
ls: cannot access /foo: No such file or directory
asidirop@aetos:~$ cat file1
20112xeim-adopse.tar.bz2
arx
arxeio2
asd
ask3erg4
cake
fff
file1
file1.txt
........

τότε έχουμε ένα εντελώς διαφορετικό σχήμα ανακατευθύνσεων σε σχέση με την προηγούμενη περίπτωση. Πρώτα γίνεται η ανακατεύθυνση της εξόδου λαθών προς την κανονική έξοδο ( 2>&1). Κατά τη συγκεκριμένη χρονική στιγμή η κανονική έξοδος δεν έχει αλλάξει ακόμη και "δείχνει" προς το τερματικό. Σε δεύτερο βήμα γίνεται η ανακατεύθυνση της κανονικής εξόδου προς το αρχείο file1. Όμως τελικά η έξοδος λαθών παραμένει να "δείχνει" προς το τερματικό ().

Αλλαγή της εξόδου λαθών προς την κανονική έξοδο και της κανονικής εξόδου προς αρχείο.
Διασωλήνωση Pipelining

Διασωλήνωση (Pipelining)

Στο Unix υπάρχει ένα ειδικού τύπου αρχείο (Βλέπε και ) το οποίο ονομάζεται pipe (σωλήνα). Ένα αρχείο τύπου pipe είναι ουσιαστικά μια δίοδος δεδομένων. Σε αυτού του τύπου τα αρχεία πρέπει μια διεργασία να γράφει και μια άλλη (ακόμη και η ίδια, αλλά δεν έχει πρακτική χρήση) να διαβάζει. Αυτός ο τύπος αρχείων είναι τύπου FIFO (First-In First-Out). Έτσι ό,τι γράφει η πρώτη διεργασία το διαβάζει η δεύτερη με την ίδια σειρά. Εδώ να σημειωθεί ότι υπάρχουν διαφορές στην εσωτερική υλοποίηση των pipes στις διάφορες εκδόσεις του unix. Στο linux υλοποιούνται μέσω του pipefs αλλά δεν αντιστοιχούν κατά ανάγκη σε πραγματικό χώρο στον δίσκο.

Μπορούμε να ανακατευθύνουμε την κανονική έξοδο μιας εντολής Α σε ένα αρχείο pipe και την κανονική είσοδο μιας εντολής Β στο ίδιο αρχείο pipe. Με αυτόν τον τρόπο, ό,τι τυπώνει η εντολή Α θα το διαβάζει η εντολή Β. Αυτό επιτυγχάνεται με το σύμβολο "|" (pipe), χωρίς να ορίσει ο χρήστης όνομα για αυτό το αρχείο:

Α | Β

Η παραπάνω εντολή, λοιπόν, δημιουργεί ένα αρχείο pipe. Σε αυτό το αρχείο γράφει η εντολή Α και διαβάζει η εντολή Β. Έτσι πρακτικά, η έξοδος της εντολής Α γίνεται είσοδος για την εντολή Β.

Στη γενική περίπτωση μπορούν να συνδυαστούν απεριόριστες εντολές μέσα σε μια συνεχόμενη διασωλήνωση. Έτσι στο παρακάτω παράδειγμα () η διεργασία Α στέλνει την έξοδό της ως είσοδο στη διεργασία Β. Η διεργασία Β στέλνει την έξοδό της στη διεργασία C και αυτό θα μπορούσε να συνεχιστεί με περισσότερες διεργασίες.

Α | Β | C
Βασική μορφή διασωλήνωσης.

Εδώ πρέπει να παρατηρηθεί ότι με τη διασωλήνωση (|) αλλάζει μόνο η κανονική έξοδος της εντολής και όχι η έξοδος λαθών. Έτσι, η έξοδος λαθών για όλες τις διεργασίες του παραπάνω παραδείγματος παραμένει όπως ήταν, δηλαδή αυτό που κληρονομήθηκε από το γονικό κέλυφος, δηλαδή το τερματικό.

Ας δούμε μερικά παραδείγματα. Έστω η απλή περίπτωση:

asidirop@aetos:~$ ls | wc
    7    7   42
asidirop@aetos:~$

Όπως φαίνεται στο , το κέλυφος δημιουργεί δυο θυγατρικές διεργασίες, την ls και την wc. Δημιουργείται ένα pipe στο οποίο γράφει η ls και από το οποίο διαβάζει η wc. Η εντολή ls θα γράψει στο pipe τη λίστα με τα ονόματα των αρχείων. Η wc θα διαβάσει αυτή τη λίστα από την κανονική της είσοδο. Η λειτουργία της wc είναι να μετρά γραμμές, λέξεις, χαρακτήρες. Έτσι θα τα μετρήσει (αυτά που θα διαβάσει από την είσοδό της) και θα τυπώσει στην κανονική έξοδο (δηλαδή στο τερματικό) τους τρεις αριθμούς.

Παράδειγμα διασωλήνωσης με ls και wc.

Ενδιαφέρον έχει η περίπτωση που μια από τις εντολές που υπάρχουν σε μια ακολουθία εντολών με διασωληνώσεις παρουσιάσει κάποιο σφάλμα. Ας επαναλάβουμε την προηγούμενη ακολουθία εντολών με τέτοιο τρόπο ώστε η πρώτη να δώσει μήνυμα σφάλματος:

asidirop@aetos:~$ ls /foo | wc
access /foo: No such file or directory
      0     0     0
asidirop@aetos:~$
Παράδειγμα διασωλήνωσης με ls και wc (περίπτωση λάθους).

Αυτό που συμβαίνει είναι να εμφανιστεί στο τερματικό μήνυμα σφάλματος και η εντολή wc να εμφανίσει τρία μηδενικά. Θα ρωτούσε κάποιος: «αφού η πρώτη εντολή έδωσε σφάλμα, γιατί εκτελείται και η επόμενη εντολή; Και γιατί η επόμενη εντολή εμφανίζει μηδενικά;»

OK Σε μια ακολουθία εντολών με διασωλήνωση, οι εντολές (διεργασίες) εκτελούνται παράλληλα.

Δηλαδή οι δυο διεργασίες ξεκινούν σχεδόν ταυτόχρονα, άρα κατά την ενεργοποίηση της δεύτερης δεν είναι γνωστό το αποτέλεσμα της πρώτης. Έτσι, λοιπόν, είναι αναπόφευκτο να εκτελεστούν και οι δυο εντολές. Αυτό που συμβαίνει φαίνεται σχηματικά στο . Η εντολή "ls /foo" τυπώνει στην έξοδο λαθών το μήνυμα σφάλματος. Η έξοδος λαθών αντιστοιχεί στο τερματικό, άρα το μήνυμα σφάλματος εμφανίζεται στο τερματικό. Στην κανονική έξοδό της η εντολή ls δεν θα τυπώσει κάτι, δηλαδή 0 bytes. Η διεργασία που αντιστοιχεί στην wc θα διαβάσει από την κανονική της είσοδο 0 bytes (δηλαδή κατευθείαν τον χαρακτήρα ελέγχου End-Of_File), και αυτά θα μετρήσει, δηλαδή μηδέν γραμμές, μηδέν λέξεις, μηδέν χαρακτήρες.

Ασκήσεις για εξάσκηση

Στόχος

Εξοικείωση με τον χειρισμό διεργασιών, ανακατεύθυνση, διασωλήνωση, φίλτρα.

Άσκηση 1

  1. Χρησιμοποιήστε την εντολή ps, για να δείτε τις διεργασίες που εκτελούνται στο σύστημα με όλες τις δυνατές επιλογές (π.χ. ps , ps –ef, ps –al, ps -aldef κλπ).
  2. Στη συνέχεια χρησιμοποιήστε την εντολή kill ή kill -9 σε κάποια από τις ενεργές διεργασίες. Τι παρατηρείτε;
  3. Ανοίξτε δυο τερματικά (τοπικά, όχι απομακρυσμένα). Από το ένα τερματικό σας εκτελέστε την εντολή:
    dolphin.
    Θα εκτελεστεί ο FileExplorer του KDE. Από το άλλο τερματικό, εκτελώντας την εντολή ps ux βρείτε το PID που αντιστοιχεί στη διεργασία του dolphin. Στείλτε στη διεργασία το σήμα STOP. (Αν το PID που βρήκατε είναι το 1234, δώστε την εντολή: kill –STOP 1234). Τι συνέβη με την εφαρμογή; Δοκιμάστε να τη χρησιμοποιήσετε, να κάνατε στο παράθυρο της εφαρμογής resize, minimize κτλ.
    Στείλτε το σήμα CONT στην ίδια διεργασία. Τι συνέβη;
    Στείλτε το σήμα TERM στην ίδια διεργασία. Τι συνέβη;
  4. Συνδεθείτε με ssh στον ιδρυματικό εξυπηρετητή (server). Εκτελέστε την εντολή ps auxw. Εντοπίστε μια διεργασία που δεν ανήκει σε σας και στείλτε της το σήμα KILL (π.χ. kill –KILL 1234). Τι συνέβη;
  5. Από την έξοδο της εντολής ps auxw μπορείτε να βγάλετε συμπεράσματα για
    1. Τις ενέργειες που κάνουν αυτήν τη στιγμή οι χρήστες?
    2. Τις υπηρεσίες (services) που εκτελούνται στο μηχάνημα?

Άσκηση 2

Μια διεργασία όταν εκτελείται από ένα τερματικό, τότε «παίρνει» τον έλεγχο του τερματικού, δηλαδή ό,τι πληκτρολογήσουμε θα διαβαστεί από τη διεργασία (αν η διεργασία δεν θέλει να διαβάσει από το τερματικό, τότε ό,τι πατάμε παραμένει στον buffer του τερματικού μέχρι κάποιος να το διαβάσει). Το shell δεν μπορεί να διαβάσει από το τερματικό μέχρι να αποδεσμεύσει το τερματικό η διεργασία.

  1. Ανοίξτε ένα τερματικό (τοπικά, όχι απομακρυσμένα). Από το τερματικό δώστε πάλι την εντολή kcalc. Το πρόγραμμα «Κομπιουτεράκι» εκτελείται. Στο τερματικό δεν μπορούμε να δώσουμε εντολές. Όταν πληκτρολογούμε, δεν γίνεται τίποτε. Πατήστε τα πλήκτρα Cntrl-Z (συμβολίζεται με ).

    Το στέλνει στην τρέχουσα διεργασία το σήμα STOP.

    Πλέον το παράθυρο του kcalc δεν αντιδρά στις κινήσεις μας.

    To κέλυφος έχει τη δυνατότητα να χειριστεί τις διεργασίες που εκτελέσαμε μέσα από αυτό. Τις ονομάζει jobs. Ένα job είναι μια διεργασία που εκτελέστηκε από το κέλυφος και σταμάτησε (ή μπήκε στο παρασκήνιο). Πατώντας , η τρέχουσα διεργασία γίνεται job.

    asidirop@dellpc:~$ kcalc
    ^Z
    [1]+  Stopped                 kcalc
    asidirop@dellpc:~$
    

    Τα jobs έχουν τη δική τους αρίθμηση από το κέλυφος. Στην παραπάνω περίπτωση είναι το jobs [1]. To + μας δηλώνει ότι είναι το τρέχον job.

  2. Δώστε την εντολή (από το ίδιο τερματικό) :
    kwrite &
    

    To & στο τέλος μιας εντολής δηλώνει στο κέλυφος να εκτελέσει την εντολή, και να τη βάλει να εκτελείται στο παρασκήνιο (δηλαδή η εντολή δεν θα μπορεί να διαβάσει από το τερματικό, αν το θελήσει). Το τερματικό παραμένει στον έλεγχο του κελύφους.

  3. Δώστε την εντολή:
    jobs
    

    μας δείχνει όλα τα jobs του τρέχοντος κελύφους και το status του καθενός. Αν η έξοδος από την εντολή jobs είναι η:

    asidirop@dellpc:~$ jobs
    [1]+  Stopped                 kcalc
    [2]-  Running                 kwrite &
    

    δώστε την εντολή:

    bg %1
    

    δηλαδή % και τον αριθμό του job που αντιστοιχεί στο σταματημένο job.

    Η εντολή bg στέλνει το σήμα CONT στη διεργασία που αντιστοιχεί, και τη βάζει να εκτελείται στο παρασκήνιο.

    Εκτελέστε πάλι την εντολή jobs και δώστε την εντολή:

    fg %1
    

    H εντολή fg στέλνει το σήμα CONT στη διεργασία που αντιστοιχεί, και την βάζει να εκτελείται στο προσκήνιο, δηλαδή της δίνει τον έλεγχο του τερματικού.

    Πατήστε τα πλήκτρα Cntrl-C (συμβολίζεται ^C).

    To ^C στέλνει στην τρέχουσα διεργασία το σήμα TERM.

    Η εφαρμογή kcalc τερματίστηκε. Τώρα ως “job” έχουμε μόνο το kwrite. Δώστε την εντολή:

    kcharselect &
    

    Τώρα έχουμε δυο jobs που τρέχουν. Κλείστε το τερματικό από το οποίο τρέξατε τα προηγούμενα jobs (πατώντας στο παράθυρο το κουμπί για κλείσιμο). Το bash, όταν τερματίζεται, τερματίζει και όλα τα jobs του (στέλνει σε όλα τα jobs το σήμα SIGHUP). Εάν δεν θέλουμε ένα job να τερματιστεί με την έξοδο από το κέλυφος, τότε πρέπει να δώσουμε την εντολή disown %x (όπου x το job number).

    H εντολή disown αποδεσμεύει ένα job από το τρέχον shell. H διεργασία, όμως, παραμένει σε εκτέλεση.

Άσκηση 3

Να βρεθεί το αποτέλεσμα της εκτέλεσης των παρακάτω εντολών :
# 1
who > file1
# 2
cat file1
# 3
wc file1
# 4
wc < file1
# 5
ls –l file1
# 6
echo "Hello world" > file2
# 7
more file2
# 8
wc file2
# 9
sort < file1 > file3
# 10
cat file3

Ποια είναι η διαφορά της εντολής 3 από την 4;

Οι εντολές wc, grep, sort (και όλες οι αντίστοιχες) συνήθως ονομάζονται εντολές φίλτρα. Αυτές οι εντολές (εάν δεν τις δοθεί ως όρισμα όνομα αρχείου) διαβάζουν δεδομένα από την κανονική είσοδο και τυπώνουν τα αποτελέσματα στην κανονική έξοδο.

Δώστε την εντολή:

wc

Θα νομίσετε ότι το τερματικό «κόλλησε». Ωστόσο, δεν κόλλησε. Η διεργασία που αντιστοιχεί στην εντολή περιμένει να διαβάσει από την κανονική είσοδο. Η κανονική είσοδος (εφόσον δεν ορίσαμε διαφορετικά) είναι το τερματικό. Μόνο που η εντολή δεν μας εμφανίζει κάποια προτροπή (prompt) όπως το κέλυφος, για να το αντιληφθούμε.

Πληκτρολογήστε κείμενο. Πότε θα σταματήσει να διαβάζει η διεργασία;

Όταν ένα πρόγραμμα διαβάζει από την κανονική είσοδο, διαβάζει με τον ίδιο ακριβώς τρόπο με τον οποίο θα διάβαζε δεδομένα από ένα αρχείο. Αν μέσα από ένα πρόγραμμα θέλαμε να διαβάσουμε όλα τα περιεχόμενα ενός αρχείου, θα διαβάζαμε byte-byte ή γραμμή-γραμμή, μέχρι να φτάσουμε στο τέλος του αρχείου. Όταν διαβάζοντας ένα αρχείο φτάσουμε στο τέλος του και δεν υπάρχουν άλλα δεδομένα, τότε το λειτουργικό στέλνει έναν ειδικό χαρακτήρα στο πρόγραμμά μας που ονομάζεται “End-Of-File” και συνήθως συμβολίζεται με το EOF. Τότε το πρόγραμμα αντιλαμβάνεται ότι δεν υπάρχει κάτι άλλο να διαβάσει από το αρχείο.

Το ίδιο κάνει και η εντολή wc όταν διαβάζει από την κανονική είσοδο (αλλά ακόμη και όταν διαβάζει από αρχείο, η συμπεριφορά είναι ίδια). Διαβάζει συνεχώς μέχρι να φτάσει στον ειδικό χαρακτήρα EOF. Αυτόν τον ειδικό χαρακτήρα, μπορούμε να τον δημιουργήσουμε από το πληκτρολόγιο (και άρα να τον διαβάσει η εντολή) πατώντας Cntrl-D (^D). Μόλις πατήσουμε ^D, η διεργασία θα σταματήσει να διαβάζει και θα μας εμφανίσει το αποτέλεσμα.

Δώστε την εντολή:

grep test

Η εντολή grep θα αναζητήσει τη συμβολοσειρά “test”. Πού όμως; Εφόσον δεν ορίσαμε αρχείο, τότε θα διαβάσει από την κανονική είσοδο (stdin), δηλαδή το τερματικό.

Πληκτρολογήστε μερικές γραμμές, ανάμεσα σε αυτές και μερικές που να περιέχουν το "test". Τι παρατηρείτε; Πατήστε ^D ώστε να ολοκληρωθεί η εντολή.

Άσκηση 4

Να βρεθεί το αποτέλεσμα της εκτέλεσης των παρακάτω εντολών :

# 1
ls | wc -l
# 2
who | wc -l
# 3
ls *.c | wc -l
# 4
who | sort | more
# 5
ls /tmp | wc -l
# 6
ls /ttt | wc –l

Ποια είναι η διαφορά στην περίπτωση (5) με (6); Στην περίπτωση (6) η wc μετράει το μέγεθος του μηνύματος σφάλματος;

Άσκηση 5

  1. Βρείτε τα αρχεία του τρέχοντος καταλόγου και εμφανίστε τα, ταξινομημένα με βάση το μέγεθος σε φθίνουσα σειρά (δείτε το man της εντολής sort).
  2. Εμφανίστε τα περιεχόμενα του αρχείου /etc/passwd με κεφαλαίους χαρακτήρες. (δείτε το man της εντολής tr).
  3. Βρείτε τα αρχεία που το όνομά τους ξεκινάει με d και εμφανίστε τα ονόματά τους με κεφαλαία γράμματα σε φθίνουσα αλφαβητική σειρά.
  4. Μετρήστε πόσοι κατάλογοι υπάρχουν στον τρέχοντα κατάλογο.
  5. Μετρήστε πόσοι χρήστες υπάρχουν στο σύστημα (μετρήστε τις γραμμές του /etc/passwd).
  6. Μετρήστε πόσοι χρήστες του αετού (ή ενός συστήματος με πολλούς χρήστες) έχουν username που ξεκινάει με a και τελειώνει σε p.
  7. Βρείτε τη διεργασία με το μεγαλύτερο PID (θυμηθείτε τις εντολές sort, head, tail).
  8. Βρείτε το αρχείο (από τον τρέχοντα φάκελο) με το μεγαλύτερο μέγεθος.

Αναφορές