Μια διεργασία (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 Ο πυρήνας διατηρεί στη μνήμη του μια λίστα με όλες τις διεργασίες, τις οποίες και χειρίζεται. Για κάθε διεργασία ο πυρήνας διατηρεί ένα σύνολο πληροφοριών:
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
είναι αντίστοιχη εντολή με την 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
Κατά την εκκίνηση ενός υπολογιστή:
init
. Αυτή, ανάλογα με τις ρυθμίσεις που είναι αποθηκευμένες θα ενεργοποιήσει όλες τις υπόλοιπες διεργασίες στο σύστημά μας.
Όταν τερματίσει η init, τότε συμβαίνει shutdown - το κλείσιμο του λειτουργικού. 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
Ένα σήμα είναι μια μέθοδος για επικοινωνία με μια διεργασία. Σήματα χρησιμοποιούνται στα συστήματα Unix και σε όλα τα λειτουργικά που ακολουθούν το πρότυπο POSIX. Ένα σήμα είναι μια ασύγχρονη ενημέρωση της διεργασίας ότι συνέβη ένα γεγονός (event). Όταν φτάνει ένα σήμα για μια διεργασία, ο πυρήνας διακόπτει την κανονική εκτέλεση της διεργασίας και εκτελείται ο αντίστοιχος signal handler. Signal handler είναι μια συνάρτηση της διεργασίας που θα χειριστεί το συγκεκριμένο σήμα. Για κάθε σήμα ορίζονται διαφορετικοί signal handlers. Όταν ολοκληρωθεί η εκτέλεση της συνάρτησης signal handler, η διεργασία επιστρέφει στην κανονική της εκτέλεση, στο σημείο που σταμάτησε. Εάν μια διεργασία λάβει ένα σήμα για το οποίο δεν έχει οριστεί signal handler, τότε εκτελείται ο προκαθορισμένος από το Λειτουργικό Σύστημα.
Κάθε σήμα, αναπαρίσταται με κάποιον αριθμό. Η αρίθμηση μπορεί να διαφέρει από σύστημα σε σύστημα. Στον πίνακα φαίνεται η αντιστοιχία σημάτων και των αντίστοιχων κωδικών.
Σήμα | Περιγραφή | Αριθμός στο "Linux x86" |
---|---|---|
SIGABRT | Process aborted | 6 |
SIGALRM | Signal raised by alarm | 14 |
SIGBUS | Bus error: "access to undefined portion of memory object" | 7 |
SIGCHLD | Child process terminated, stopped (or continued*) | 17 |
SIGCONT | Continue if stopped | 18 |
SIGFPE | Floating point exception: "erroneous arithmetic operation" | 8 |
SIGHUP | Hangup | 1 |
SIGILL | Illegal instruction | 4 |
SIGINT | Interrupt | 2 |
SIGKILL | Kill (terminate immediately) | 9 |
SIGPIPE | Write to pipe with no one reading | 13 |
SIGQUIT | Quit and dump core | 3 |
SIGSEGV | Segmentation violation | 11 |
SIGSTOP | Stop executing temporarily | 19 |
SIGTERM | Termination (request to terminate) | 15 |
SIGTSTP | Terminal stop signal | 20 |
SIGTTIN | Background process attempting to read from tty ("in") | 21 |
SIGTTOU | Background process attempting to write to tty ("out") | 22 |
SIGUSR1 | User-defined 1 | 10 |
SIGUSR2 | User-defined 2 | 12 |
SIGPOLL | Pollable event | 29 |
SIGPROF | Profiling timer expired | 27 |
SIGSYS | Bad syscall | 31 |
SIGTRAP | Trace/breakpoint trap | 5 |
SIGURG | Urgent data available on socket | 23 |
SIGVTALRM | Signal raised by timer counting virtual time: "virtual timer expired" | 26 |
SIGXCPU | CPU time limit exceeded | 24 |
SIGXFSZ | File size limit exceeded | 25 |
Μπορεί ο χρήστης (ή μια διεργασία) να στείλει ένα σήμα σε μια διεργασία με την εντολή 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=xtermLANG LANGUAGE Μεταβλητή Περιβάλλοντος LANG Μεταβλητή Περιβάλλοντος LANGUAGE Τοπικές Ρυθμίσεις Διεργασίας
Ένα πολύ χρήσιμο σύνολο μεταβλητών περιβάλλοντος είναι οι μεταβλητές που αφορούν τη γλώσσα και τα σύμβολα εμφάνισης, πχ αν στην ώρα θα υπάρχει το π.μ. ή το a.m. Αυτές είναι οι:
LANG
,LANGUAGE
,LC_CTYPE
,LC_NUMERIC
,LC_TIME
,LC_COLLATE
,LC_MONETARY
,LC_MESSAGES
,LC_PAPER
,LC_NAME
,LC_ADDRESS
,LC_TELEPHONE
,LC_MEASUREMENT
,LC_IDENTIFICATION
.Αυτές οι μεταβλητές περιβάλλοντος χρησιμοποιούνται από τις βιβλιοθήκες του συστήματος και των γλωσσών προγραμματισμού για τη σωστή εμφάνιση μηνυμάτων.
Βασικές μεταβλητές είναι οι 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, stderr
,cin, cout, cerr
,STDOUT, STDIN, STDERR
,System.in, System.out, System.err
.Στις περισσότερες γλώσσες προγραμματισμού, όταν παραλείπεται η αναφορά σε αρχείο, εννοείται η κανονική είσοδος (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) |
Το Λειτουργικό Σύστημα κρατάει σε κάθε θέση του πίνακα διάφορες πληροφορίες που αντιστοιχούν στο ανοιχτό αρχείο όπως τη θέση του Κέρσορα στο αρχείο, την κατάσταση ανοίγματος (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 Ροές Εισόδου-Εξόδου Ανακατεύθυνση
Ο χρήστης μπορεί να δώσει διάφορες οδηγίες προς το κέλυφος, ώστε να αλλάξει τις προκαθορισμένες ροές εισόδου-εξόδου. Έτσι, χρησιμοποιώντας το σύμβολο > ορίζεται αλλαγή της κανονικής εξόδου. Μετά από το σύμβολο > πρέπει να ακολουθεί όνομα αρχείου. Έτσι, η κανονική έξοδος της εντολής θα ανακατευθυνθεί στο αρχείο που ορίστηκε. Στο παρακάτω παράδειγμα, η εντολή 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:~$
Υπάρχει η γενική πολιτική: μέσα από ένα πρόγραμμα αν θέλουμε να τυπώσουμε ένα μήνυμα λάθους, τότε αυτό θα πρέπει να τυπωθεί στην έξοδο λαθών (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
Στο 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 είναι να μετρά γραμμές, λέξεις, χαρακτήρες. Έτσι θα τα μετρήσει (αυτά που θα διαβάσει από την είσοδό της) και θα τυπώσει στην κανονική έξοδο (δηλαδή στο τερματικό) τους τρεις αριθμούς.
Ενδιαφέρον έχει η περίπτωση που μια από τις εντολές που υπάρχουν σε μια ακολουθία εντολών με διασωληνώσεις παρουσιάσει κάποιο σφάλμα. Ας επαναλάβουμε την προηγούμενη ακολουθία εντολών με τέτοιο τρόπο ώστε η πρώτη να δώσει μήνυμα σφάλματος:
asidirop@aetos:~$ ls /foo | wc access /foo: No such file or directory 0 0 0 asidirop@aetos:~$
Αυτό που συμβαίνει είναι να εμφανιστεί στο τερματικό μήνυμα σφάλματος και η εντολή wc να εμφανίσει τρία μηδενικά. Θα ρωτούσε κάποιος: «αφού η πρώτη εντολή έδωσε σφάλμα, γιατί εκτελείται και η επόμενη εντολή; Και γιατί η επόμενη εντολή εμφανίζει μηδενικά;»
Σε μια ακολουθία εντολών με διασωλήνωση, οι εντολές (διεργασίες) εκτελούνται παράλληλα. |
Δηλαδή οι δυο διεργασίες ξεκινούν σχεδόν ταυτόχρονα, άρα κατά την ενεργοποίηση της δεύτερης δεν είναι
γνωστό το αποτέλεσμα της πρώτης. Έτσι, λοιπόν, είναι αναπόφευκτο να εκτελεστούν και οι δυο εντολές.
Αυτό που συμβαίνει φαίνεται σχηματικά στο .
Η εντολή "ls /foo
" τυπώνει στην έξοδο λαθών το μήνυμα σφάλματος.
Η έξοδος λαθών αντιστοιχεί στο τερματικό, άρα το μήνυμα σφάλματος εμφανίζεται στο τερματικό.
Στην κανονική έξοδό της η εντολή ls δεν θα τυπώσει κάτι, δηλαδή 0 bytes.
Η διεργασία που αντιστοιχεί στην wc θα διαβάσει από την κανονική της είσοδο 0 bytes (δηλαδή κατευθείαν τον
χαρακτήρα ελέγχου End-Of_File), και αυτά θα μετρήσει, δηλαδή μηδέν γραμμές, μηδέν λέξεις, μηδέν χαρακτήρες.
Εξοικείωση με τον χειρισμό διεργασιών, ανακατεύθυνση, διασωλήνωση, φίλτρα.
ps
, για να δείτε τις διεργασίες που εκτελούνται στο σύστημα με όλες τις δυνατές επιλογές (π.χ. ps , ps –ef, ps –al, ps -aldef
κλπ).kill
ή kill -9
σε κάποια από τις ενεργές διεργασίες. Τι παρατηρείτε;dolphin
.ps ux
βρείτε το PID που αντιστοιχεί στη διεργασία του dolphin
. Στείλτε στη διεργασία το σήμα STOP. (Αν το PID που βρήκατε είναι το 1234, δώστε την εντολή: kill –STOP 1234). Τι συνέβη με την εφαρμογή; Δοκιμάστε να τη χρησιμοποιήσετε, να κάνατε στο παράθυρο της εφαρμογής resize, minimize κτλ.
ps auxw
. Εντοπίστε μια διεργασία που δεν ανήκει σε σας και στείλτε της το σήμα KILL (π.χ. kill –KILL 1234
). Τι συνέβη;
ps auxw
μπορείτε να βγάλετε συμπεράσματα για
Μια διεργασία όταν εκτελείται από ένα τερματικό, τότε «παίρνει» τον έλεγχο του τερματικού, δηλαδή ό,τι πληκτρολογήσουμε θα διαβαστεί από τη διεργασία (αν η διεργασία δεν θέλει να διαβάσει από το τερματικό, τότε ό,τι πατάμε παραμένει στον buffer του τερματικού μέχρι κάποιος να το διαβάσει). Το shell δεν μπορεί να διαβάσει από το τερματικό μέχρι να αποδεσμεύσει το τερματικό η διεργασία.
kcalc
. Το πρόγραμμα «Κομπιουτεράκι» εκτελείται. Στο τερματικό δεν μπορούμε να δώσουμε εντολές. Όταν πληκτρολογούμε, δεν γίνεται τίποτε. Πατήστε τα πλήκτρα Cntrl-Z
(συμβολίζεται με ^Ζ
).
Το ^Ζ
στέλνει στην τρέχουσα διεργασία το σήμα STOP.
To κέλυφος έχει τη δυνατότητα να χειριστεί τις διεργασίες που εκτελέσαμε μέσα από αυτό. Τις ονομάζει jobs. Ένα job είναι μια διεργασία που εκτελέστηκε από το κέλυφος και σταμάτησε (ή μπήκε στο παρασκήνιο). Πατώντας ^Ζ
, η τρέχουσα διεργασία γίνεται job.
asidirop@dellpc:~$ kcalc ^Z [1]+ Stopped kcalc asidirop@dellpc:~$
Τα jobs έχουν τη δική τους αρίθμηση από το κέλυφος. Στην παραπάνω περίπτωση είναι το jobs [1]. To +
μας δηλώνει ότι είναι το τρέχον job.
kwrite &
To & στο τέλος μιας εντολής δηλώνει στο κέλυφος να εκτελέσει την εντολή, και να τη βάλει να εκτελείται στο παρασκήνιο (δηλαδή η εντολή δεν θα μπορεί να διαβάσει από το τερματικό, αν το θελήσει). Το τερματικό παραμένει στον έλεγχο του κελύφους.
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 διεργασία, όμως, παραμένει σε εκτέλεση.
# 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
ώστε να ολοκληρωθεί η εντολή.
Να βρεθεί το αποτέλεσμα της εκτέλεσης των παρακάτω εντολών :
# 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
μετράει το μέγεθος του μηνύματος σφάλματος;
man
της εντολής sort
)./etc/passwd
με κεφαλαίους χαρακτήρες. (δείτε το man
της εντολής tr
)./etc/passwd
).sort, head, tail
).