Password management - the script

Giorgos Keramidas keramida at ceid.upatras.gr
Wed Dec 21 17:11:08 EET 2005


On 2005-12-21 14:33, Pavlos Parissis <p_pavlos at freemail.gr> wrote:
> > Αν πάλι βαριέστε να το δείτε μου φένεται απόλυτα φυσιολογική
> > αντίδραση :-)
>
> Αν και δεν έχω ιδέα απο python είπα να κάνω ένα απλό τέστ απο
> περιέργεια , δίνοντας echo "dddd" |python show-pass.py
>
> Password DB
> Don't use this programm if you are not authorized to do so (hit ctrl-C to exit)
>
> ?word, number, +, * >******Bad Command******
> ?word, number, +, * >Traceback (most recent call last):
>   File "show-pass.py", line 126, in ?
>     cmd=left(raw_input(colst+'?word, number, +, * '+colend+'>').strip(),255)
> EOFError: EOF when reading a line

Γι αυτό εγώ αν έγραφα κάτι σαν 'shell' σε Python, θα ξεκινούσα κάπως έτσι:

     1  #!/usr/bin/env python
     2
     3  import sys
     4
     5  def shellcmd(s):
     6      print "## shellcmd \"" + s + "\""
     7      return s
     8
     9  def main():
    10      while True:
    11          s = sys.stdin.readline()
    12          # When we reach EOF, just quit
    13          if not s:
    14              return
    15          try:
    16              s = s.strip().rstrip()
    17              shellcmd(s)
    18          except ShellCommandError, msg:
    19              print "command error: " + msg.strip().rstrip()
    20
    21  # Start at the main loop of the program.
    22  main()

Η main() δεν χρειάζεται να είναι πιο περίπλοκη από ένα απλό:

        - read command
        - run command
        - catch errors
        - repeat

Η shellcmd() μπορεί να αρχίσει να μεγαλώνει εύκολα, αν της προσθέσεις
ένα dictionary με keys τα 'commands' και value για κάθε command ένα
implementation function (ή ακόμα καλύτερα ένα stack από implementation
functions, ώστε να μπορείς να κάνεις 'nest'/'overload' την υλοποίηση
κάθε shellcmd απλά κάνοντας append() και pop() τις overloaded
υλοποιήσεις:

Ετσι μπορείς να κάνεις ένα 'shell', του οποίου οι υποστηριζόμενες
εντολές και το τι κάνει η κάθε εντολή μπορεί να είναι εντελώς
επεκτάσιμα.

Κάτι άλλο που μπορεί να βολέψει αν φτιάξεις το shell σου με πιο object
oriented τρόπο (όπου 'objects' είναι τα features κι οι εντολές του)
είναι ότι έτσι θα είναι πιο ξεκάθαρο σε κάθε σημείο ποια είναι τα πιθανά
errors και τι πρέπει να κάνεις γι αυτά.

Ενα κάπως καλύτερο παράδειγμα από shell command-loop είναι αυτό:

     1  #!/usr/bin/env python
     2
     3  import sys
     4
     5  class ShellInvalidCommand(Exception):
     6      def __init__(self, value):
     7          self.value = value
     8      def __str__(self):
     9          return repr(self.value)
    10
    11  class ShellUnknownCommand(Exception):
    12      def __init__(self, value):
    13          self.value = value
    14      def __str__(self):
    15          return repr(self.value)
    16
    17  class ShellCommandError(Exception):
    18      def __init__(self, value):
    19          self.value = value
    20      def __str__(self):
    21          return repr(self.value)
    22
    23  def cmd_ls(e):
    24      print "    ls(" + ":".join(e) + ")"
    25      return 0
    26
    27  def shellcmd(s):
    28      # All the commands supported by this mini-shell.
    29      cmds = {'ls':cmd_ls}
    30
    31      # Nothing to do, fail.
    32      if not s:
    33          raise ShellInvalidCommand, "no command string"
    34
    35      # Split the command string in words, and use the first word as the
    36      # command name.
    37      words = []
    38      try:
    39          s = s.expandtabs()
    40          words = s.split(' ')
    41      except:
    42          raise ShellCommandError, s
    43      if len(words) < 1:
    44          raise ShellCommandError, s
    45
    46      # Look up the command implementation function in the cmds{} dictionary.
    47      try:
    48          fptr = cmds[words[0]]
    49      except:
    50          raise ShellUnknownCommand, s
    51
    52      # Run the command implementation function.
    53      try:
    54          print "running " + str(fptr)
    55          fptr(words)
    56      except:
    57          ShellCommandError, s
    58      return 0
    59
    60  def main():
    61      while True:
    62          sys.stdout.write("pyshell> ")
    63          sys.stdout.flush()
    64          s = sys.stdin.readline()
    65
    66          # When we reach EOF, just quit
    67          if not s:
    68              break
    69
    70          try:
    71              s = s.strip().rstrip()
    72              shellcmd(s)
    73          except ShellInvalidCommand, e:
    74              print "pyshell: invalid shell command: " + str(e)
    75          except ShellUnknownCommand, e:
    76              print "pyshell: unknown shell command: " + str(e)
    77          except ShellCommandError, e:
    78              print "pyshell: command execution error: " + str(e)
    79          except:
    80              print "pyshell: unknown error, aborting"
    81              return None
    82
    83      # When the read-eval-exec loop stops, the shell dies
    84      sys.stdout.write("\n")
    85      sys.stdout.flush()
    86      print "pyshell: exiting."
    87      return 0
    88
    89  # Start at the main loop of the program.
    90  main()

Το οποίο όταν το τρέξεις θα δεις κάτι σαν αυτό:

    pyshell> foo
    pyshell: unknown shell command: 'foo'
    pyshell> bar
    pyshell: unknown shell command: 'bar'
    pyshell> ls
    running <function cmd_ls at 0x64bca0>
        ls(ls)
    pyshell> ls -la foo bar
    running <function cmd_ls at 0x64bca0>
        ls(ls:-la:foo:bar)
    pyshell> ^D
    pyshell: exiting.

Πρόσεξε ότι η cmd_ls() παίρνει όντως ένα πίνακα με τα 'words' της
εντολής, οπότε μπορεί να χειριστεί όπως θέλει τα arguments που
πήρε στο prompt.

Πολύ απλοϊκό ως shell, σίγουρα, αλλά μπορείς να κάνεις αρκετά
όμορφα πράγματα με ένα read-eval-exec loop :-)





More information about the Linux-greek-users mailing list