Monday 14 January 2008

Linux Terminal - Μάθημα 7ο - Εισαγωγή στο Scripting

Κελύφη(shells) εντολών και scripting

Ο μεταφραστής εντολών του Linux, ονομάζεται κέλυφος, επειδή αυτό που αφήνει καί φαίνεται είναι μόνο το εξωτερικό του, εσωτερικά υπάρχουν πολυ περισσότερα από οσα αντιλαμβάνεται ο χρήστης με μια πρώτη ματιά. Τα συστήματα τύπου UNIX, σαν το Linux, είναι μοναδικά στο να αφήνουν τον χρήστη να επιλέξει το κέλυφος εντολών που θα χρησιμοποιεί. Τα περισσότερα λειτουργικά συστήματα έχουν τον μεταφραστή εντολών ενσωματωμένο στο ίδιο το λειτουργικό σύστημα, μη αφήνοντας άλλη επιλογή στον χρήστη. Σε αντίθεση με αυτά στα συστήματα τύπου UNIX, ο μεταφραστής εντολών είναι ανέξαρτητος απο το λειτουργικό σύστημα, το οποίο ειναί σε θέση να λειτουργησεί και χωρίς τον μεταφραστή εντολών.

Επιπλέον καθένα απο τα διαθέσιμα κελύφη παρέχει τις δικές του λειτουργίες και χαρακτηριστικά και φυσικά την δική του γλώσσα scripting. Εμείς θα εξετάσουμε τις δυνατότητες scripting που μας δίνει το bash/sh και θα δούμε περιεκτίκα τις διαφοροποιήσεις του με τα άλλα κελύφη εντολών.

Το περιβάλλον(environment) εντολών του κελύφους

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

Οι μεταβλητές στα διάφορα κελύφη

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

1. SH/BASH

Η σύνταξη για να θέσουμε μια μεταβλητή στο sh ή στο bash έχει την ακόλουθη μορφή:

ΜΕΤΑΒΛΗΤΗ=τιμή.

Κατά σύμβαση οι μεταβλητές του περιβάλλοντος υποδηλώνονται με ΚΕΦΑΛΑΙΑ για να διαχωρίζονται από τις εντολές του κελύφους ή του συστήματος. Όταν προσδιορίζουμε μια μεταβλητή στο κέλυφος εντολών τότε ορίζουμε την μεταβλητή αυτή μονο για την διάρκεια της τρέχουσας session και εξασφαλίζουμε την ορατότητα της μόνο από το τρέχον κέλυφος.
Για να κάνουμε την μεταβλήτη αυτή ορατή σε υπό-κελύφη χρησιμοποιούμε την εντολή export, συντάσσοντας:

export ΜΕΤΑΒΛΗΤΗ.

Η εντολή export μπορεί να συνδυαστεί με την δήλωση της μεταβλητής: export ΜΕΤΑΒΛΗΤΗ=τιμή .

2. C SHELL

Για να θέσουμε μεταβλητές στο κέλυφος C ή κάποια παραλλαγή του, χρησιμοποιούμε την εσωτερική εντολή setenv.

setenv ΜΕΤΑΒΛΗΤΗ τιμή

Οπώς διαπιστώνετε ο τρόπος που δηλώσαμε την μεταβλητή είναι διαφορετικός από ότι στο SH. Δοκιμάζοντας την σύνταξη του SH στο Κέλυφος C, Θα πάρετε φυσικά μήνυμα λάθους.
Σε αντίθεση με το κέλυφος Sh, στο κελύφος C, μπορούμε και να ξε-θέσουμε μια μεταβλητή χρησιμοποιώντας την εσωτερική εντολή unsetenv.

unsetenv ΜΕΤΑΒΛΗΤΗ

Για να τυπώσουμε όλες τις μεταβλητες του περιβάλλοντος, χρησιμοποιούμε την εντολή env. Ενώ για να τυπώσουμε την τιμή μιας συγκεκριμένης μεταβλήτης χρησιμοποιούμε την εντολή

echo $ΜΕΤΑΒΛΗΤΗ ή printenv ΜΕΤΑΒΛΗΤΗ

Aliases

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

alias la ls -la

Αυτό θα όριζε την εντολή la, η οποία θα ήταν ισοδύναμη με την εντολή ls -la. Ομώς θα πρέπει να έχετε υπόψη ότι όπως οι μεταβλήτες, ετσι και οι εντολές που ορίζουμε, παυουν να υφιστανταί μόλις κάνουμε logout από το σύστημα εκτός και αν τις τοποθετήσουμε σε κάποιο αρχείο που περίεχει τους ορισμούς για το περιβάλλον. Το σε ποίο αρχείο θα τις τοποθετήσουμε εξαρτάται και πάλι από το κέλυφος που χρησιμοποίουμε.

Τα αρχεία περιβάλλοντος

Κάθε φορά που εκτελείται ένα κέλυφος, αναζητεί ένα συγκεκριμένο αρχείο, στο οποίο υπάρχουν ορισμένες οι μεταβλητές και οι aliases που θα πρέπει να ορίσει. Όπως είπαμε κάθε κέλυφος έχει το δικό του αρχείο για αυτή τη δουλεία. Έτσι:

ΚΕΛΥΦΟΣ SH ΚΑΙ BASH
Στα sh/bash το αρχείο βρίσκεται στο home κατάλογο του χρήστη και ονομάζεται $HOME/.profile ή $HOME/.bashrc (η τελεία πριν το όνομα του αρχείου υποδηλώνει ότι το αρχείο είναι κρυφό, ενώ με $HOME το κέλυφος υποδηλώνει το μονοπάτι που βρίσκεται ο κατάλογος home για σας δηλ συνήθως το /home/username).
Το αρχείο .profile είναι ένα απλό αρχείο κειμένου το οποίο πρέπει να διορθώσετε με έναν επεξεργαστή κειμένου που ΔΕΝ κάνει αυτόματη μορφοποίηση (η μορφοποίηση γίνεται με χρήση αόρατων ascii χαρακτήρων που σε ένα αρχείο διαμόρφωσης θα προκάλουσαν πιθανώς λάθη.) H διαφορά των δύο αρχείων είναι ότι το .profile τρέχει μια φορά ενώ το .bashrc κάθε φορά που καλούμε το bash

Μετά αυτό το μικρό σχόλιο είμαστε έτοιμοι να ανοίξουμε τον αγαπημένο μας επεξεργαστή κειμένου (δηλαδή το vi) και να κάνουμε κάποιες τροποποιήσεις στο .profile. To αρχείο .profile θα μοιάζει κάπως έτσι:

# τα σχόλια γράφονται μετά τον χαρακτήρα #.
# Θέτουμε το μονοπάτι πρώτης αναζήτησης εντολών κάπως έτσι:
PATH="$PATH:/home/nexx0r/scripts/:/usr/games"
# στην πάνω γραμμή με $PATH έχει συμβολίσει το σύστημα το προκαθορισμένο μονοπάτι οπού περιέχονται οι εντολές
# του συστήματος, ενώ με : έχω προσθέσει στη συνέχεια δύο δικά μου μονοπάτια. Οποιαδήποτε εντολή πληκτρολογήσω
# στο σύστημα μου χωρίς το σχετικό της μονοπάτι, και δεν είναι σε κάποιους από τους καταλόγους που όρισα εγώ ή το
# σύστημα θα δώσει μήνυμα λάθους.
PS1="[\u@\h ]\\$ "
# Η παραπάνω γραμμή καθορίζει ότι αν η εντόλη είναι τόσο μεγάλη που καταλαμβάνει και δεύτερη θα πρέπει να το
# υποδηλώσει με τον χαρακτήρα \ ακολουθόμενο απο το enter. Όπως επίσης και την μορφή που θα έχει το shell prompt,
# δηλαδή [username@hostname]$
USER='id -un'
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
HOSTNAME='/bin/hostname'
HISTSIZE=1000
HISTFILESIZE=1000
#Οι δύο παραπάνω γραμμές καθορίζουν το μέγεθος του ιστορικού εντολών που θα κρατηθεί.
# Μπορούμε να προσθέσουμε aliases ή ακόμα και custom συναρτήσεις...
# Functions

function ff()
{ find . -type f -iname '*'$*'*' -ls ; }

# Aliases
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias mkdir='mkdir -p'

# η ακόμα και χρώματα με κωδικούς διαφυγής
red='\e[0;31m'
RED='\e[1;31m'
blue='\e[0;34m'
BLUE='\e[1;34m'
NC='\e[0m' # καθαρισμός χρώματος


# Τέλος με την export κάνουμε γνωστά στο σύστημα τα ορίσματά μας
export PATH PS1 USER LOGNAME MAIL \
HOSTNAME HISTSIZE HISTFILESIZE INPUTRC

ΚΕΛΥΦΟΣ C
Το αρχείο που χρησιμοποιεί το κέλυφος C είναι το .cshrc και έχει ελαφρά πολυπλοκότερη σύνταξη:
# Τα σχόλια εξακολουθούν να είναι έτσι


if($?PATH) then
setenv PATH "{PATH}:/home/nexx0r/scripts/:/usr/games"
else
setenv PATH "/bin/:usr/bin/:/home/nexx0r/scripts/:/usr/games"
endif
# Στις 5 παραπάνω γραμμές απλά δήλωσα το path. Δεν μπορείτε να πείτε το C shell είναι πιο ψαγμένο!

if($?prompt) then
if($?tcsh) then
set prompt='[%n@m %c]$ '
else
set prompt=\['id -nu'@'hostname -s'\]\$\
endif
endif

# Στις 7 παραπάνω γραμμές απλά δήλωσα το shell prompt!

setenv HOSTNAME '/bin/hostname'
set history=1000
κτλ

Επιτέλους λίγο Scripting!

Μέτα την μίκρη αλλά απαραίτητη εισαγώγη μας, ήρθε η στιγμή που όλοι περιμέναμε, να μπούμε δηλαδή στο scripting καθεαυτό. Όσα περιγραψούμε παρακάτω, δουλεύουν στο κέλυφος sh, στο κέλυφος bash, στο korn κέλυφος και τους κλώνους τους.

To scripting για το κέλυφος δίνει στον διαχειριστή ή χρηστη του συστήματος την δυνατότητα να αυτοματοποιήσει ορισμένες διαδικασίες και να κάνει την ζωή του πιο εύκολη (ή δύσκολη!). Τα scripts είναι εύκολα να δημιουργηθούν και είναι αμέσα διαθέσιμα. Για να ξεκινήσετε το scripting, η πρώτη γραμμή που πρέπει να προσδιορίσετε είναι το κέλυφος για το οποίο προορίζεται το script, μετά τους χαρακτήρες #!. Δηλαδή:

#!/bin/sh

Μετά την γραμμή αυτή μπορούμε να κάνουμε οτι θέλουμε με το script μας αρκεί να υπακούσουμε φυσικά τους συντακτικούς κανόνες του κέλυφους. Ο πρώτος κανόνας που θα μάθουμε είναι πότε χρησιμοποίουμε ' και πότε ". Το οποίο είναι και το πρώτο πράγμα πού συνήθως μπερδεύουν όσοι ξεκινάνε μια γλώσσα script.
Χρησιμοποιούμε τα ' για να αποτρέψουμε το κέλυφος από το να μεταφράσει το κενό. Πχ στην δήλωση μεταβλήτων:

ΜΕΤΑΒΛΗΤΗ='τιμή1 τιμή2'

Χρησιμοποιούμε τα " για να περικλύσουμε για παράδειγμα το όνομα μια μεταβλητής. Πχ:

ΜΕΤΑΒΛΗΤΗ1="$ΜΕΤΑΒΛΗΤΗ2"

Οπου η ΜΕΤΑΒΛΗΤΗ1 παίρνει την τιμή που έχει η ΜΕΤΑΒΛΗΤΗ2.

Ελεγχος Εκφράσεων if-fi

Ο έλεγχος μιας έκφρασης μπορεί να γίνει με δύο τρόπους. Χρησιμοποιώντας την εντολή If ή περικλύωντας την έκφραση σε αγκύλες []. Η εντολή If έχει το δίκο της σώμα του οποίου το ξεκίνημα υποδηλώνει το if και κλείνει το fi. Ο έλεγχος των εκφράσεων εξαρτάται από το τύπο των μεταβλήτων που ελέγχονται. Και σε αντίθεση με τις συνήθεις γλώσσες προγραμματισμού, εδώ θεωρούμε την συνθήκη αληθής όταν δώσει 0 και ΟΧΙ 1. Ακολούθεί ο πίνακας με τις ποιο χρησίμες εκφράσεις:

Τύπος Δεδομένου Έλεγχος Περιγραφή Παράδειγμα
Συμβολοσειρά (string) =

!=

Ελέγχει αν δύο string είναι ίσα

Ελέγχει αν δύο string δεν είναι ισα

if["$var1"="$var2"];

then echo "Match Found" fi

if["$var1"!="$var2"];

then echo "Match not Found" fi

Αριθμητικό -eq

-nq

-lt

-gt

-ge

Ελέγχει αν δύο νούμερα είναι ίσα

Ελέγχει αν δύο νούμερα δεν είναι ίσα

Ελέγχει αν το πρώτο είναι μικρότερο

Ελέγχει αν το πρώτο είναι μεγαλύτερο

Ελέγχει αν το πρώτο είναι μεγαλύτερο ή ίσο

if[$var1 -eq $var2];

then echo "They are equal" fi

if[$var1 -nq $var2];

then echo "They are not equal" fi

if[$var1 -lt $var2];

then echo "var1

if[$var1 -gt $var2];

then echo "var1>var2" fi

if[$var1 -ge $var2];

then echo "var1>=var2" fi

Αρχεία -f

-d

-r

-w

-x

Έλεγχος για ύπαρξη αρχείου

Ελεγχος για ύπαρξη καταλόγου

Ελεγχος αν το αρχείο έχει άδεια ανάγνωσης

Ελεγχος αν το αρχείο έχει άδεια εγγραφής

Ελεγχος αν το αρχείο έχει αδεία εκτέλεσης

if [-f "$filename"];

then echo "file exists!" fi

if [-d "$dirname"];

then echo "dir exists!" fi

if [-r "$filename"];

then echo "We can read" fi

if [-w "$filename"];

then echo "We can write!" fi

if [-x "$filename"];

then echo "Its Executable!" fi

Λογικές Πράξεις !

-a

-o

Αρνήση Έλεγχου

Λογικό KAI

Λογικό Η'

if [! -w "$filename"];

then echo "We can't write it!" fi

if [-f "$filename" -a -w "$filename2"];

then echo "it Exists and can be written!" fi

if [-f "$filename" -o -w "$filename2"];

then echo " either exists or can be written!" fi

Η εντολή case

Με την εντολή case μπορούμε να ελέγξουμε αν μια σύνθηκη ικάνοποιεί κάποιες προυποθέσεις. Παραδείγματος χάριν, θέλουμε να έλεγξουμε την κατάληξη που έχει ένα αρχείο και να κάνουμε κάποιες εργασίες ανάλογα με αυτή. Κάτι τέτοιο με την χρήση της if θα γίνοταν πολύπλοκο, με την case ειναι παιχνιδάκι:

case "$file" in

*.c) echo "File is C source, so we compile with c compiler"
;;
*.cc|*.cpp) echo "File is C++ source, so we compile with c++ compiler"
;;
*.h|*.hpp) echo "File is Header, so we don't compile it"
;;
Με το ;; υποδήλωνουμε οτι τέλειωσαν οι ενέργειες στην συγκεκριμένη περιπτώση. Οπώς βλέπετε δουλευεί και ο λογικος τελεστής | με τον οποίο μπορούμε να πετύχουμε ακόμα πιο πολύπλοκους ελέγχους.

H δημιουργία βρόχων

Οπως συμβαίνει στις περισσότερες γλώσσες προγραμμάτισμου, έτσι και εδώ έχουμε στην διαθέση μας τους αγαπήμενους μας βρόχους while και for.

WHILE
Ο βρόχος while επαναλαμβάνει ότι περιέχει στο σώμα του για όσο η συνθήκη που δώσαμε είναι αλήθης. Η σύνταξη είναι κάπως έτσι:

while [Συνθήκη ]

do
εντολές
done
Παράδειγμα:
i=0

while [$i -lt 5]
do
echo $i
i='expr "$i" + 1'
done
Σε αυτό το παράδειγμα όσο το i ήταν μικρότερο του 5, τυπωνόταν η τιμή του στην οθόνη και στη σύνεχεια αυξάνοταν κατα 1. Την αύξηση του i κατα 1 την πετύχαμε με την χρήση της εντολής expr, παρατηρήστε την διαφόρα στη χρήση των ' και των ".

FOR
Ας δούμε την σύνταξη του for με ένα ενδιαφέρον παράδειγμα:

c=1

for file in 'ls -R /home/*'
do
c='expr "$c" + 1'
done
echo "$c files are inside /home and its subdirectories"
Θα πρέπει να παρατηρήσουμε οτι πάρα την ευελίξια της η for στο κέλυφος Bourne, έχει την ιδιομορφία να εκτελεί μια επανάληψη ακόμα και όταν η συνθήκη δεν ικανοποιείται.

Χρήσιμες εντολές

Η εντολή sleep

Η εντολή sleep κάνει το κέλυφος να περιμένει για κάποιο αριθμό δευτερολέπτων.

πχ sleep 2 # αναμονή 2 δευτερόλεπτα

H εντολή read

Η εντολή read γεμίζει μια μεταβλήτη με είσοδο του χρήστη απο το πληκτρολόγιο.

πχ read answer # το προγραμμά σταματάει την εκτελέση του μεχρί να δώσουμε τιμή + enter

H εντολή exit

Η εντολή exit σταματάει την εκτέλεση του script και επιστρέφει μια τιμή ελέγχου στο κελύφος.

πχ exit 0 # επιστρέφουμε στο κέλυφος οτι η εκτέλεση του script ήταν επιτυχής

Η δυνατότητα επιστροφής μιας τίμης μας βοήθαει να καταλάβουμε σε ποίο σημείο του script κάναμε λάθος, και να το αποσφαλματώσουμε.

Επίσης με την εντολή Help, μπορούμε να παρουμε βοήθεια

πχ $help while

while: while COMMANDS; do COMMANDS; done
Expand and execute COMMANDS as long as the final command in the
`while' COMMANDS has an exit status of zero.


Αποσφαλματώνοντας το script σας

Για να εκτέλεσουμε το script σε περιβάλλον αποσφαλμάτωσης χρησιμοποιούμε το ειδίκο ορίσμα -x κατα την εκτέλεση του. Αυτό μπορούμε να το προσδιορίσουμε στην αρχή του script, αρχίζωντας έτσι:

#!/bin/sh -x ,

ή κάτα την εκτέλεση, τρέχωντας το μέσα σε κάποιο άλλο κέλυφος:

πχ sh -x myscript.sh .

Όταν εκτελούμε το script σε περιβάλλον αποσφαλμάτωσης πριν την εκτέλεση κάποιας εντολής την τυπώνει στην οθόνη, έτσι μπορούμε να δούμε τις τιμές των μεταβλητών καθώς αυτές επεξεργάζονται από το script.

Keywords: Linux, Terminal, Shell, Commands, Syntax, Tips n Tricks, Terminal Series,Scripting,

bash,aliases,alias,if,while,for,case,read,sleep,exit,debug,variables

No comments: