Δημοσιεύτηκε: 19 Σεπ 2012, 22:48
από lucinos


Δείτε το παραπάνω βιντεάκι, δεν έχει μόνο ιστορικό ενδιαφέρον.

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

Θέλω όμως να το πάω λίγο μακρύτερα. Είναι γενικότερα καλή ιδέα ακόμα και ένα πρόγραμμα γραφικού περιβάλλοντος να βασίζεται σε εργαλεία που τρέχουν στην γραμμή εντολών.
Ως ένα παράδειγμα να θυμίσω το rsync, αυτό τρέχει σε γραμμή εντολών και φυσικά δεν είναι πρόβλημα ένα εύχρηστο πρόγραμμα τού γραφικού περιβάλλοντος να το χρησιμοποιήσει. Ένα πρόγραμμα που τρέχει σε γραμμή εντολών μπορείς να το τρέξεις χωρίς προβλήματα σε διαφορετικά γραφικά περιβάλλοντα, ακόμα και χωρίς γραφικό περιβάλλον. Η μεταφορά του από ένα σύστημα σε άλλο είναι πολύ μικρότερο πρόβλημα και η χρήση του από άλλα προγράμματα είναι πολύ ευκολότερη.
Ακόμα και αν το πρόγραμμα εξορισμού έχει να κάνει με γραφικό περιβάλλον και πάλι είναι πολύ χρήσιμο οι επιλογές του να υπάρχουν στην γραμμή εντολών. Ως θετικό παράδειγμα δίνω τον vlc. Για να πάρετε μια ιδέα δώστε την εντολή:
Κώδικας: Επιλογή όλων
vlc -H

Οι επιλογές είναι τόσο πολλές που δεν μπορείτε να τις δείτε όλες, για να τις δείτε όλες χρησιμοποιήστε την less,

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

Ένα πολύ ιδιαίτερο χαρακτηριστικό τού unix (που έχει εξαχθεί και στα υπόλοιπα συστήματα) είναι οι σωληνώσεις και οι ανακατευθύνσεις. Μια ιδέα για το πόσο ισχυρό εργαλείο είναι παίρνετε από το βιντεάκι. Πολλές δουλειές που κάποιος προγραμματιστής θα υπέθετε ότι χρειάζονται ιδιαίτερο πρόγραμμα μπορούν να γίνουν με συνδυασμό προγραμμάτων μέσω σωλήνων πολύ απλά και εύκολα. Ένα χαρακτηριστικό που πρέπει να σημειωθεί είναι ότι τα προγράμματα που συνδέονται μέσω σωλήνα, τρέχουν ταυτόχρονα. Δηλαδή στο τερματικό δώστε:
Κώδικας: Επιλογή όλων
ps

Θα δείτε ότι στο τερματικό σας τρέχουν το bash (o φλοιός) και το πρόγραμμα ps.
Τρέχοντας όμως:
Κώδικας: Επιλογή όλων
ps|less

όλως περιέργως θα δείτε και την less. Δηλαδή δεν τρέχει η ps, παράγει μια έξοδο και μετά ξεκινάει η less, που την παίρνει σαν είσοδο, αλλά τρέχουν και οι δύο μαζί και συνδέεται η έξοδος τής μίας στην είσοδο τής άλλης.

Για να το δούμε στην πράξη, φανταστείτε ότι κάποιος έχει γράψει το ακόλουθο πρόγραμμα:

Κώδικας: Επιλογή όλων
#!/usr/bin/python3
#rizes.py
'''Υπολογισμός ριζών δευτεροβάθμιας εξίσωσης'''

import math

print ('Για την εξίσωση α*x^2 + β*x + γ = 0 δώστε:')
a = float (input ('α = ') )
b = float (input ('β = ') )
c = float (input ('γ = ') )

diakrinousa = b**2 - 4*a*c
if diakrinousa < 0:
    print ('Η εξίσωση δεν έχει λύση')
elif diakrinousa == 0:
    print ('βρέθηκε μία λύση:')
    print ('ρ = ', -b / (2.*a) )
else:
    print ('βρέθηκαν δύο λύσεις:')
    print ('ρ1 = ', (-b - math.sqrt(diakrinousa)) / (2.*a) )
    print ('ρ2 = ', (-b + math.sqrt(diakrinousa)) / (2.*a) )



αυτή η «διαδραστικότητα» δεν θεωρείται γενικά καλή ιδέα στο unix αλλά ακόμα και αυτό συνεργάζεται με σωληνώσεις και γενικότερα ανακατευθύνσεις:
αν για παράδειγμα έχουμε ένα αρχείο data.dat με περιεχόμενο:
Κώδικας: Επιλογή όλων
1
4
4


Η εντολή:
Κώδικας: Επιλογή όλων
./rizes.py < data.dat

θα δώσει έξοδο:
Κώδικας: Επιλογή όλων
Για την εξίσωση α*x^2 + β*x + γ = 0 δώστε:
α = β = γ = βρέθηκε μία λύση:
ρ =  -2.0

Εδώ παίρνουμε μάλλον μια ιδέα γιατί δεν είναι επιθυμητή αυτή η διαδραστικότητα στο unix. Είναι λίγο πιο δύσκολο να αξιοποιηθεί η έξοδος από άλλο πρόγραμμα. Λειτουργεί όμως!
Επίσης αρχίζουμε να εκτιμούμε και τον τελεστή "<". Δεν έχει καμμία σημασία η γλώσσα που έχει γραφτεί το πρόγραμμα, ούτε πώς έχει γραφτεί το πρόγραμμα. Ο φλοιός το αντιμετωπίζει σαν μαύρο κουτί.

Ας δούμε άλλο ένα πρόγραμμα σε python:
Κώδικας: Επιλογή όλων
#!/usr/bin/python3
#tetragwno.py

while True :
    try :
        x = input()
        x = float(x)
        print(x**2)
    except EOFError:
        break
   

Αυτό παίρνει έναν αριθμό και τον υψώνει στο τετράγωνο, επαναλαμβάνει την διαδικασία μέχρι να συναντήσει το τέλος τού αρχείου. Δοκιμάστε να τρέξετε το πρόγραμμα. Σάς θυμίζει κάτι η συμπεριφορά του (την cat ίσως) ; Έτσι όχι μόνο μπορείτε να δοκιμάζετε το πρόγραμμα εύκολα αλλά έχετε και μια πολύ καλή συνεργασία με τις ανακατευθύνσεις. Εδώ νομίζω πολλοί κάνουν λάθος. Όταν θέλουν να γράψουν ένα πρόγραμμα που διαβάζει ένα αρχείο, επεξεργάζεται τις τιμές (πχ κάνει έναν υπολογισμό) και γράφει το αποτέλεσμα σε ένα άλλο αρχείο, πάνε και ψάχνουν τις σχετικές εντολές για την συγκεκριμένη γλώσσα προγραμματισμού για να τις χρησιμοποιήσουν. Αυτό γενικά είναι κακή πρακτική. Όχι μόνο παιδεύονται περισσότερο για να κάνουν μια δουλειά που άνετα την κάνει ο φλοιός, αλλά κάνουν το πρόγραμμά τους πολύ πιο δύσκαμπτο. Το πρόγραμμα είναι δεσμευμένο να λειτουργεί με τον συγκεκριμένο τρόπο. Αν αντίθετα χρησιμοποιηθεί απλά η κανονική είσοδος και έξοδος έχουμε ένα πολύ πιο ευέλικτο πρόγραμμα να λειτουργήσει ευέλικτα χωρίς να χρειάζεται να το αλλάζουμε ούτε να το μεγαλώσουμε για να αλλάξουμε πράγματα όπως από που εισάγει δεδομένα και πού τα εξάγει.

Οι σωληνώσεις και οι ανακατευθύνσεις φυσικά δεν είναι πανάκεια. Τα παραπάνω προγράμματα υποθέτουν ότι τούς δίνουμε καλούς αριθμούς. Τι γίνεται όμως αν για παράδειγμα δώσουμε κάτι που δεν είναι αριθμός; Η python θα πετάξει σφάλμα (συγκεκριμένα ValueError). Αν αυτό δεν είναι επιθυμητό μια λύση είναι να χρησιμοποιήσουμε ένα πρόγραμμα που θα φιλτράρει τα δεδομένα ώστε η έξοδος να μην έχει πρόβλημα. Αυτό το πρόγραμμα μπορεί να συνδεθεί με σωλήνα. Όμως αυτή η λύση μπορεί να μην είναι η επιθυμητή αλλά να θέλουμε έναν πιο ευαίσθητο χειρισμό. Εδώ φαίνονται τα όρια τών σωληνώσεων. Οι σωληνώσεις μπορεί μεν να προσφέρουν λύσεις σε φαινομενικά πολύπλοκα προβλήματα αλλά στην τελική το μόνο που κάνουν είναι να συνδέουν την είσοδο και την έξοδο, έχουν μόνο μια κατεύθυνση στον τρόπου που λειτουργούν. Στις άλλες περιπτώσεις δεν εφαρμόζονται. Διαφορετικά θα μπορούσαμε να έχουμε αποκλειστικά μικρά απλά προγράμματα που συνδέονται με σωλήνες και τα μεγάλα προγράμματα θα θεωρούνταν κακή προγραμματιστική πρακτική. Δεν συμβαίνει όμως αυτό. Το ίδιο και με τις ανακατευθύνσεις προς και από αρχεία. Το γεγονός ότι μπορούμε να γράφουμε εύκολα την έξοδο σε αρχεία και να εισάγουμε εύκολα δεδομένα από αρχεία μέσω τών ανακατευθύνσεων δεν σημαίνει ότι αν θέλουμε να κάνουμε κάτι περισσότερο περίπλοκο δεν χρειαζόμαστε τις εντολές για διάβασμα και γράψιμο σε αρχεία. Από την άλλη όμως αποφύγετε να κάνετε την δουλειά έτσι αν πραγματικά δεν είναι αναγκαίο και ακόμα και αν είναι αναγκαίο υπολογίστε την δυνατότητα να χρησιμοποιηθούν οι κανονική έξοδος και είσοδος με ανακατευθύνσεις και σωληνώσεις.

Δείτε το ακόλουθο πρόγραμμα:
Κώδικας: Επιλογή όλων
#! /usr/bin/python3
# dyn.py

import sys

def dynamis(x, n, N):
    try:
        return repr( round (float(x) ** float(n), N) )
    except ValueError:
        return 'NAN'
    except ZeroDivisionError:
        return 'INF'

def main():
    n = float(sys.argv[1])
    try:
        N = int(sys.argv[2])
    except IndexError:
        N = 6
       
    while True:       
        try:
            print( dynamis( input(), n, N ) )
        except EOFError:
            break
       
if __name__ == '__main__':
    main()   


Γενικά είναι καλή ιδέα να αρθρώνετε έτσι τα προγράμματά σας ώστε να διαχωρίζεται η βασική λειτουργία (εδώ η συνάρτηση dynamis) από την διεπαφή (εδώ η συνάρτηση main) έτσι μπορείτε και να αλλάξετε εύκολα την συνάρτησή σας ώστε να την προσαρμόσετε σε νέες ανάγκες (ή για αποσφαλμάτωση) αλλά και να την χρησιμοποιήσετε από άλλα προγράμματα (εδώ μέσω τής python με την import) οπότε έχετε μια πολύ πιο ισχυρή διεπαφή (και όχι μόνο την γραμμή εντολών). Στο παραπάνω πρόγραμμα επίσης βλέπουμε και την χρήση επιλογών από την γραμμή εντολών (ο πίνακας sys.argv). Τρέχει με εντολές όπως:
Κώδικας: Επιλογή όλων
./dyn.py -1.2 10

οπότε υψώνει στην -1.2 με 10 δεκαδικά ψηφία ακρίβεια.

Ο φλοιός (όπως το bash) μπορεί να χρησιμοποιηθεί και ο ίδιος σαν γλώσσα προγραμματισμού και θεωρητικά έχει τα αναγκαία στοιχεία όπως βρόχους και ελέγχους ροής, αλλά ως γλώσσα προγραμματισμού είναι ιδιαιτέρως ακατάλληλος. Θα έλεγα φρίκη. Έτσι χρειαζόμαστε τις άλλες γλώσσες προγραμματισμού για τις προγραμματιστικές μας ανάγκες. Δεν προτείνεται ούτε για να μάθει κάποιος προγραμματισμό. Κατά την γνώμη μου κάποιος είναι πολύ καλό να μάθει όσο γίνεται γρηγορότερα τα βασικά στην γραμμή εντολών (αυτά πρακτικά που έχω βάλει στην κυρίως σειρά μαθημάτων) ώστε να κατανοήσει καλύτερα το σύστημα αλλά μετά να μην συνεχίσει απευθείας σε περισσότερο φλοιό μαθαίνοντας για τα σενάρια. Για κάτι τέτοιο είναι πιο ακατάλληλος για να μάθει κάποιος προγραμματισμό από βασικές γλώσσες όπως η C ή η FORTRAN. Το καλύτερο είναι να μάθει τα βασικά σε μια γλώσσα που θέματα όπως η χρήση συναρτήσεων, η χρήση μεταβλητών, οι βρόχοι και ο έλεγχος ροής είναι ιδιαιτέρως εύκολα και η ιδανική γλώσσα είναι μάλλον η Python. Μετά από αυτό έχει τα βασικά εφόδια ώστε να πάρει όποια κατεύθυνση θέλει. Μπορεί να ασχοληθεί με οποιαδήποτε γλώσσα όπως η C, η FORTRAN, η Java, η Python, η Perl, η Ruby, η Bash κλπ.

Πρόταση για βιβλίο: The Art of Unix Programming