Skip to content

Commit 88c5623

Browse files
committed
Shell V0.1
1 parent 9ecec86 commit 88c5623

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Shell building project using python.
2+
3+
NOTE TO SELF:
4+
1.PYTHON IS CASE SENSITIVE.
5+
2.For some reason program doesnt terminate on sys.exit(0) or return 0 in the main() for some reason while using visual studio but works fine in the terminal.
6+
3.Used def func for each command.
7+
4.Split is is used to cut commands into multiple parts. and then dictionary can be used to match it out.
8+
5.regex is the way to go but too complex.
9+
6. os.path.isfile: to check if file is present. os.access(path,os.X_OK) to check that the user privilages are enough.
10+
7.shutil is used for high level operations for the file.
11+
8.os.[] has important file handing functions.
12+
9.isdir checks for directory and isfile checks for a executable file.
13+
10.Join is can be used to join variables in a list with desired separator.
14+
11.prompttoolkit is useful during user input operations.
15+
16+
v[0.1]
17+
Task-To-Implement:
18+
1.REPL (READ-EVAL-PRINT-LOOP): executes command after command like a terminal does.
19+
2.EXIT: Implemented status 0 on typin "exit 0".
20+
3.ECHO: 1. implemented to read echo and differentiate from illegal words like "echo34" or "echo%" for now. and changed both of them to be executed as functions.(echo strips the first 5 words of each message)
21+
2.Rewored echo to recognizse seprators.
22+
3.Reworked echo to recognize Redirect stdout & stdin
23+
24+
4.TYPE: Shows if or not the command is present in the shell.
25+
5.CUSTOM COMMANDS: 1. checks for command and command path in bin. if present executes the command.
26+
2. Reworked to distinguished quoted commands.
27+
6.PWD: outputs current working directory from os.
28+
7.CD: 1.changes directory on absolute path, relative and ~ for home.
29+
2.Reworked cd to recognize seprators.
30+
8.AUTOCOMPLETE: autocompletes all builting commands.
31+

app/main.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import sys
2+
import os
3+
import shutil #shell utilities.
4+
import shlex #Simple lexical analysis.
5+
from prompt_toolkit import prompt #toolkit used to autocomplete words.
6+
from prompt_toolkit.completion import WordCompleter
7+
8+
def main():
9+
#REPL
10+
completer = WordCompleter(builtin,ignore_case=True)
11+
while True:
12+
13+
# "$" initiation
14+
#Takes in an input
15+
command = prompt("$ ",completer=completer)
16+
sys.stdout.flush()
17+
18+
#Recognises status 0 on "exit 0"
19+
if command == "": #Blank input resets.
20+
main()
21+
elif command.startswith("exit"):
22+
handle_exit(command)
23+
24+
elif command.startswith("pwd"):
25+
handle_pwd(command)
26+
27+
elif command.startswith("cd"):
28+
handle_cd(command)
29+
30+
elif command.startswith("echo"):
31+
handle_echo(command)
32+
33+
elif command.startswith("type"):
34+
handle_typecmd(command)
35+
36+
elif handle_systemcommand(command):
37+
os.system(command) #Automatically prints output but print(os.system(command)) causes it to return code 0.
38+
else:
39+
#f"{}" stands for formmated string
40+
print_cmd_error(command)
41+
42+
def debug():
43+
print("works!")
44+
45+
def handle_systemcommand(message):
46+
message = shlex.split(message)
47+
if shutil.which(message[0]):
48+
return True
49+
return False
50+
51+
#Prints error message
52+
def print_cmd_error(message):
53+
print(f"{message}: command not found")
54+
sys.stdout.flush()
55+
56+
#ECHO command to print out the message
57+
def handle_echo(message): #Searches for "<" anad ">" in echo command and redirects to os shell.
58+
if "<" in message or ">" in message:
59+
os.system(message)
60+
return
61+
elif message.startswith("echo "):
62+
message=message[5:].strip()
63+
message=shlex.split(message)
64+
print(" ".join(message))
65+
elif message == "echo":
66+
print("")
67+
else:
68+
print_cmd_error(message)
69+
70+
#EXIT command to exit the program
71+
def handle_exit(message):
72+
if len(message)<5:
73+
print_cmd_error(message)
74+
return
75+
76+
message=message.split(maxsplit=1)
77+
if len(message)==2 and message[1] =="0":
78+
#Exiting with system(0)
79+
sys.exit(0)
80+
else:
81+
print_cmd_error(message[1])
82+
83+
#All commands in shell
84+
builtin={"echo","exit","type","pwd","cd"}
85+
86+
#finding inbuilt commands and searches for given path and command in envior path.
87+
def handle_typecmd(message):
88+
#splits message into "type" & follow up "command"
89+
message = message.split(maxsplit=1)
90+
91+
#Checks if it split into two
92+
if len(message)==2:
93+
94+
#Checks for command in builtin commands
95+
if message[1] in builtin:
96+
print(f"{message[1]} is a shell builtin")
97+
return
98+
99+
#Retrive and Split current path, pathsep auto detects win or linux sepration
100+
path_dictry = os.environ.get("PATH","").split(os.pathsep)
101+
102+
103+
#Process and match the path
104+
for directory in path_dictry:
105+
Potential_path=os.path.join(directory,message[1])
106+
107+
#Is file gives boolean if the path exists
108+
#Access does the same but for if the user can has exucatable access
109+
if os.path.isfile(Potential_path) and os.access(Potential_path,os.X_OK): #Is there a file and can we access it.
110+
print(f"{message[1]} is {Potential_path}")
111+
return
112+
113+
print(f"{message[1]}: not found")
114+
else:
115+
print_cmd_error(message[0])
116+
117+
#shows current directory
118+
def handle_pwd(message):
119+
message = message.split(maxsplit=1)
120+
if len(message) > 1:
121+
print_cmd_error(message[0])
122+
return
123+
elif message[0] == "pwd":
124+
#used to check current directory
125+
print(os.getcwd())
126+
return
127+
else:
128+
print_cmd_error(message[0])
129+
130+
#handles cd commands for absoute, relative and HOME
131+
def handle_cd(message):
132+
message = message.split(maxsplit=1)
133+
if (len(message) < 2):
134+
print_cmd_error(message[0])
135+
return
136+
if(len(message) == 2) and (message[1]=="~"):
137+
os.chdir(os.path.expanduser("~"))
138+
return
139+
140+
if ((len(message) >= 2) and (os.path.isdir(message[1]) == True)):
141+
os.chdir(message[1])
142+
return
143+
else:
144+
print(f"cd: {message[1]}: No such file or directory")
145+
return
146+
147+
if __name__ == "__main__":
148+
main()
149+
432

0 commit comments

Comments
 (0)