Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a command to search for a pattern in a file/standard input #5

Merged
merged 4 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions pysh.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import subprocess
from utils.commands_list import *
from utils.boyer_moore_algorithm import BoyerMooreAlgorithm
import calendar
import getpass
import shutil
Expand Down Expand Up @@ -627,6 +628,24 @@ def do_diff(self, *args):
else:
print("pysh: diff: incorrect usage: try 'diff [FILE1] [FILE2]'")

def do_grep(self, *args):
commands = args[0].split()
self.save_history("grep " + " ".join(commands))
pattern = BoyerMooreAlgorithm(commands[0])

if '-f' in commands:
if os.path.exists(os.getcwd() + '/' + commands[commands.index('-f') - 1]):
with open(commands[commands.index('-f') - 1], 'r') as file:
line_number = 1
for line in file:
pattern.find_pattern(line.split(' '), True, line_number)
line_number += 1
else:
print("pysh: grep: {}: No such file or directory".format(commands[commands.index('-f') - 1]))

else:
pattern.find_pattern(commands[1:])

def do_chmod(self, *args):
gen_args = args[0].split()

Expand Down Expand Up @@ -788,6 +807,9 @@ def help_kill(self):
def help_diff(self):
print(commands_list_manual['diff'])

def help_grep(self):
print(commands_list_manual['grep'])

def help_chmod(self):
print(commands_list_manual['chmod'])

Expand Down
65 changes: 65 additions & 0 deletions utils/boyer_moore_algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from colorama import Fore

NO_OF_CHARS = 256

class BoyerMooreAlgorithm():
def __init__(self, pattern):
self.pattern = pattern
self.shift_table = [-1] * NO_OF_CHARS

# Fill the actual value of last occurrence
for char in range(len(pattern)):
self.shift_table[ord(pattern[char])] = char;

def find_pattern(self, source, file = False, line_number = 0):
source = " ".join(source)
pattern_length = len(self.pattern)
result = []
source_index = 0
while(source_index <= len(source) - pattern_length):
j = pattern_length - 1

'''
Keep reducing index j of pattern while
characters of pattern and text are matching
at this shift source_index
'''
while j >= 0 and self.pattern[j] == source[source_index+j]:
j -= 1

'''
If the pattern is present at current shift,
then index j will become -1 after the above loop
'''
if j < 0:
result.append(source_index)
'''
Shift the pattern so that the next character in text
aligns with the last occurrence of it in pattern.
The condition source_index + pattern_length < len(source) is necessary for the case when
pattern occurs at the end of text
'''
source_index += (pattern_length - self.shift_table[ord(source[source_index + pattern_length])]
if source_index + pattern_length < len(source) else 1)
else:
'''
Shift the pattern so that the bad character in source text
aligns with the last occurrence of it in pattern. The
max function is used to make sure that we get a positive
shift. We may get a negative shift if the last occurrence
of bad character in pattern is on the right side of the
current character.
'''
source_index += max(1, j - self.shift_table[ord(source[source_index+j])])

if file and result != []:
print(f"Line {line_number}: ", end = '')

previos_index = 0
for index in result:
print(source[previos_index:index], end="")
print(Fore.CYAN + source[index:index + len(self.pattern)] + Fore.RESET, end = "")
previos_index = index + len(self.pattern)

if result != []:
print('\n')
4 changes: 2 additions & 2 deletions utils/commands_list.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
commands_list = ['lf', 'ldir', 'pwd', 'cd', 'manual', 'mkdir',
'calendar', 'calc', 'whoami', 'echo', 'rm',
'cat', 'cp', 'mv', 'date', 'file', 'history',
'head', 'tail', 'touch', 'wc', 'ip', 'host', 'arch', 'ps', 'wget', 'kill', 'diff',
'chmod']
'head', 'tail', 'touch', 'wc', 'ip', 'host', 'arch', 'ps', 'wget', 'kill', 'diff', 'chmod', 'grep']

commands_list_manual = {
'exit': "Exits the shell where it is currently running. \nusage: 'exit'",
Expand Down Expand Up @@ -36,5 +35,6 @@
'wget': "Network downloader - download files from internet. \nusage: 'wget [URL]'",
'kill': "Terminate an unresponsive program. \nusage: 'kill [PID]'",
'diff': "Compares files line by line. \nusage: 'diff [FILE1] [FILE2]'",
'grep': "Utility for searching plain-text data sets for lines that match a regular expression. \nusage: 'grep [expression] [data-set] -f' {if the data-set is a file}\nusage: 'grep [expression] [data-set]' {if the data-set is an input string}",
'chmod': "Changes access permissions and the special mode flags of file system objects. \nusage: 'chmod [PERMISSIONS] [FILES]...'"
}