-2

I'm making my own shell in Python and trying to make it as user-friendly and customizable as possible. I'm having an issue when parsing command line strings though.

I have a list of args to be passed to the command.

When I try:

echo "Hello World!"

My args look like this:

['Hello World!', 'World!"']

And not this (desired output):

['Hello World!']

The issue isn't an error, just a bug in the code.

Here is my command parser (this should work on its own if you pass something into it):

import os
import imp

from rich.console import Console

def handle_command(console: Console, command: str):
    split_string = command.split(" ")
    command_name = split_string[0]
    command_name = command_name.lower()

    if command_name == "":
        return True

    args = []

    for i in range(1, len(split_string)):
        if split_string[i].startswith('"'):
            res = ""

            pos = i

            while pos <= len(split_string):
                try:
                    res += f"{split_string[pos]} "
                except IndexError:
                    console.print(f"[bold bright_red]ERR: Unterminated string in command arguments[/bold bright_red]")
                    return False
                if split_string[pos].endswith('"'):
                    break
                pos += 1

            if pos == len(split_string):
                if not split_string[pos].endswith('"'):
                    console.print(f"[bold bright_red]ERR: Unterminated string in command arguments[/bold bright_red]")
                    return False

            res = res.replace('"', "")

            args.append(res)
            continue

        args.append(split_string[i])

    commands_dir = os.path.join(os.getcwd(), "shells/Fresh/commands")
    
    if os.path.exists(commands_dir) and os.path.isdir(commands_dir):
        for f in os.listdir(commands_dir):
            if os.path.isfile(os.path.join(commands_dir, f)):
                #try:
                    cmd = imp.load_source(command_name, os.path.join(commands_dir, f))

                    if cmd.name == command_name:
                        if cmd.min_args <= len(args):
                            if cmd.max_args >= len(args):
                                cmd.run(console, args)

                                return True
                            else:
                                console.print(f"[bold bright_red]ERR: {command_name} takes a maximum of {cmd.max_args} arguments[/bold bright_red]")
                                return False
                        else:
                            console.print(f"[bold bright_red]ERR: {command_name} requires atleast {cmd.min_args} argument[/bold bright_red]")
                            return False
                #except Exception as e:
                    #console.print(f"[bold red]ERR: An error occured while running this command[/bold red]")
                    #return False

        console.print(f"[bold bright_red]ERR: Invalid or unkown command '{command_name}'[/bold bright_red]")
        return False
    else:
        raise FileNotFoundError("Commands directory is corrupted or does not exist")
Spooky
  • 81
  • 1
  • 6
  • 6
    Please read [ask] and https://ericlippert.com/2014/03/05/how-to-debug-small-programs/. Note well that this is **not a discussion forum**; "Any help would be appreciated!" is [not how the site works](https://meta.stackoverflow.com/questions/284236). We expect a specific, clear question up front, which results from your own best attempt to locate and describe a specific problem. This starts with you carefully checking what the code does, step by step, and figuring out where that diverges from your expectation. After that, *focus* on that part of the code with a [mre]. – Karl Knechtel Sep 29 '22 at 20:37
  • Does this answer your question? [Split a string by spaces -- preserving quoted substrings -- in Python](https://stackoverflow.com/questions/79968/split-a-string-by-spaces-preserving-quoted-substrings-in-python) – Abdul Aziz Barkat Oct 04 '22 at 04:23
  • Debug questions require a [mre]--cut & paste & runnable code including initialization; desired & actual output (including verbatim error messages); tags & versions; clear specification & explanation. For debug that includes the least code you can give that is code that you show is OK extended by code that you show is not OK. [ask] [Help] When you get a result you don't expect, find the first point in the execution where the state of the variables is not what you expect & say what you expected & why, justified by documentation. (Debugging fundamental.) – philipxy Oct 06 '22 at 01:21
  • Your edit does not address the feedback. – philipxy Dec 05 '22 at 06:33

2 Answers2

2

In your example,

split_string = ["echo", '"Hello', 'World!"']

So:

for i in range(1, len(split_string)):

will execute it 2 times (one for Hello and one for World)

It will first add Hello world! to args than continue and this time will add 'World!"' because it doesnt fit the

if split_string[i].startswith('"')

I think the problem here is mainly the way the tokens are interpreted. Generally, just splitting a string by spaces is not enough to parse a command correctly when it contains a string

I think you should take a look at what a Lexer is

TKirishima
  • 742
  • 6
  • 18
  • 2
    Please read [answer] and note well that this is **not a discussion forum**. Before posting an answer, make sure the question is well posed (this includes it being clear and *specific*; the code should be the minimum required to demonstrate a specific problem, and a question should be asked about it directly), and try to have a more clear idea of the problem than "maybe you should research a specific topic" (that is a red flag that the question is not appropriate). – Karl Knechtel Sep 29 '22 at 20:39
  • Please use standard spelling & punctuation. – philipxy Oct 06 '22 at 01:24
1

You are splitting the command with split_string = command.split(" "), so you will get three items ['echo', '"Hello', 'World!"'].

You iterate starting at index 1 for i in range(1, len(split_string)):.

Your code goes through and correctly parses `Hello World!', but the issue is you add this line args.append(split_string[i]) after your while loop.

Because of this it will append 'World!"' to the result, because if split_string[i].startswith('"'): will return False.

Sterling
  • 432
  • 2
  • 9
  • 4
    As with the other answer: please read [answer] - this is not a debugging service and questions like this one should be closed and not answered. – Karl Knechtel Sep 29 '22 at 20:40
  • 4
    Because the question is off topic, and answers to off topic questions are not useful and make the site worse. – Karl Knechtel Sep 29 '22 at 20:43
  • 7
    He provided actual and expected behavior, as well as provided a reproducible. The OP may not have had the insight to know how to debug the program. I was giving him this insight. I do not see what the problem is. I frankly disagree with you. – Sterling Sep 29 '22 at 20:50
  • 3
    https://meta.stackoverflow.com/questions/255459/is-it-okay-to-downvote-answers-to-bad-questions – Sterling Oct 03 '22 at 17:50