Skip to content

Instantly share code, notes, and snippets.

@fernandolopez
Last active December 14, 2020 19:49
Show Gist options
  • Save fernandolopez/6564869 to your computer and use it in GitHub Desktop.
Save fernandolopez/6564869 to your computer and use it in GitHub Desktop.
Ejemplo muy básico de un shell para ilustrar la diferencia de los comandos internos y comandos externos de los shells usados en sistemas operativos unix-like. El ejemplo no un estilo muy prolijo ni pythonico porque está pensado para ser fácil de entender para personas que no conocen el lenguaje.
#!/usr/bin/env python
#-*- encoding: utf-8 -*-
#
# Ejemplo de un shell extremadamene rudimentario e incompleto
# para ilustrar la diferencia entre comandos internos
# y comandos externos
#
import os
########################## COMANDOS INTERNOS #########################
# Implementación muy básica e incompleta de comandos internos...
# no importa si no se entiende la implementación de esta parte
def echo_cmd(args):
print(" ".join(args))
def ls_cmd(arg):
if not arg:
arg = [os.getcwd()]
try:
print("\n".join(os.listdir(arg[0])))
except OSError as ex:
print(ex)
def exit_cmd(arg):
if not arg:
arg = [0]
exit(int(arg[0]))
def help_cmd(arg):
print("Comandos internos:\n" + "\n".join(comandos_internos.keys()))
# Defino los comandos internos
comandos_internos = {
'echo': echo_cmd,
'ls': ls_cmd,
'exit': exit_cmd,
'help': help_cmd
}
################## INICIALIZANDO ALGUNAS VARIABLES ##################
# Obtengo la lista de directorios en los que se buscarán
# los comandos, para esto pido la variable de entorno $PATH
path = os.getenv('PATH').split(':')
# Si soy root la terminal muestra un numeral, sino un signo pesos
if os.getuid() == 0:
prompt = "# "
else:
prompt = "$ "
#################### LEYENDO Y EJECUTANDO COMANDOS ##################
while True:
comando = raw_input(prompt) # Leo un comando por teclado
argumentos = comando.split() # Separo la línea en "palabras"
if not argumentos:
# Si no se ingresó ningún comando vuelvo al principio
continue # Esto salta una iteración del while
nombre = argumentos[0] # Me quedo con la primer palabra
# Verifico si tengo una implementación interna del comando
if nombre in comandos_internos:
# Invoco el comando interno con todas las palabras de
# la línea excepto la primera (es decir con sus
# argumentos)
comandos_internos[nombre](argumentos[1:])
else:
path_descubierto = None
# Probablemente el usuario haya indicado
# el path completo o el path relativo al
# comando, por ejemplo /bin/ls
# en ese caso no hace falta buscar
if os.path.exists(nombre):
path_descubierto = nombre
else:
# Busco el comando en los directorios listados en la
# variable de entorno PATH
for directorio in path:
# Por ejemplo si ls no fuera interno
# y PATH=/bin:/usr/bin:/usr/local/bin
# buscaría: /bin/ls, luego /usr/bin/ls,
# luego /usr/local/bin/ls
if os.path.exists(directorio + '/' + nombre):
path_descubierto = directorio + '/' + nombre
break # Salgo del for
if path_descubierto == None:
# Si no encontramos nada...
print("Comando " + comando + " no encontrado")
else:
# Si existe lo ejecuto (para eso
# creo un nuevo proceso)
pid = os.fork()
if pid == 0:
# Si entra por acá es
# porque estoy en el
# proceso hijo
# entonces ejecuto el comando
os.execvp(
path_descubierto,
argumentos
)
else:
# Si entra por acá es
# porque estoy en el
# proceso padre
# entonces espero que
# el hijo termine de ejecutarse
os.waitpid(pid, 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment