Skip to content

Commit 2c5417b

Browse files
committed
Fixed parsing issue in case where output redirection (e.g. > file) appears before a pipe.
In that case, the pipe was given precedence even though it appeared later in the command.
1 parent 1dd2c0e commit 2c5417b

File tree

3 files changed

+52
-47
lines changed

3 files changed

+52
-47
lines changed

cmd2/cmd2.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,18 +3331,21 @@ def load_ipy(app):
33313331
help='output commands to a script file, implies -s'),
33323332
ACTION_ARG_CHOICES, ('path_complete',))
33333333
setattr(history_action_group.add_argument('-t', '--transcript',
3334-
help='output commands and results to a transcript file, implies -s'),
3334+
help='output commands and results to a transcript file,\n'
3335+
'implies -s'),
33353336
ACTION_ARG_CHOICES, ('path_complete',))
33363337
history_action_group.add_argument('-c', '--clear', action='store_true', help='clear all history')
33373338

33383339
history_format_group = history_parser.add_argument_group(title='formatting')
3339-
history_script_help = 'output commands in script format, i.e. without command numbers'
3340-
history_format_group.add_argument('-s', '--script', action='store_true', help=history_script_help)
3341-
history_expand_help = 'output expanded commands instead of entered command'
3342-
history_format_group.add_argument('-x', '--expanded', action='store_true', help=history_expand_help)
3340+
history_format_group.add_argument('-s', '--script', action='store_true',
3341+
help='output commands in script format, i.e. without command\n'
3342+
'numbers')
3343+
history_format_group.add_argument('-x', '--expanded', action='store_true',
3344+
help='output fully parsed commands with any aliases and\n'
3345+
'macros expanded, instead of typed commands')
33433346
history_format_group.add_argument('-v', '--verbose', action='store_true',
3344-
help='display history and include expanded commands if they'
3345-
' differ from the typed command')
3347+
help='display history and include expanded commands if they\n'
3348+
'differ from the typed command')
33463349

33473350
history_arg_help = ("empty all history items\n"
33483351
"a one history item by number\n"

cmd2/parsing.py

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -453,56 +453,54 @@ def parse(self, line: str, expand: bool = True) -> Statement:
453453
arg_list = tokens[1:]
454454
tokens = []
455455

456-
# check for a pipe to a shell process
457-
# if there is a pipe, everything after the pipe needs to be passed
458-
# to the shell, even redirected output
459-
# this allows '(Cmd) say hello | wc > countit.txt'
456+
pipe_to = ''
457+
output = ''
458+
output_to = ''
459+
460+
# Find which redirector character appears first in the command
461+
try:
462+
pipe_index = tokens.index(constants.REDIRECTION_PIPE)
463+
except ValueError:
464+
pipe_index = len(tokens)
465+
460466
try:
461-
# find the first pipe if it exists
462-
pipe_pos = tokens.index(constants.REDIRECTION_PIPE)
467+
redir_index = tokens.index(constants.REDIRECTION_OUTPUT)
468+
except ValueError:
469+
redir_index = len(tokens)
470+
471+
try:
472+
append_index = tokens.index(constants.REDIRECTION_APPEND)
473+
except ValueError:
474+
append_index = len(tokens)
475+
476+
# Check if output should be piped to a shell command
477+
if pipe_index < redir_index and pipe_index < append_index:
463478

464479
# Get the tokens for the pipe command and expand ~ where needed
465-
pipe_to_tokens = tokens[pipe_pos + 1:]
480+
pipe_to_tokens = tokens[pipe_index + 1:]
466481
utils.expand_user_in_tokens(pipe_to_tokens)
467482

468483
# Build the pipe command line string
469484
pipe_to = ' '.join(pipe_to_tokens)
470485

471486
# remove all the tokens after the pipe
472-
tokens = tokens[:pipe_pos]
473-
except ValueError:
474-
pipe_to = ''
487+
tokens = tokens[:pipe_index]
475488

476-
# check for output redirect
477-
output = ''
478-
output_to = ''
479-
try:
480-
output_pos = tokens.index(constants.REDIRECTION_OUTPUT)
481-
output = constants.REDIRECTION_OUTPUT
489+
# Check for output redirect/append
490+
elif redir_index != append_index:
491+
if redir_index < append_index:
492+
output = constants.REDIRECTION_OUTPUT
493+
output_index = redir_index
494+
else:
495+
output = constants.REDIRECTION_APPEND
496+
output_index = append_index
482497

483-
# Check if we are redirecting to a file
484-
if len(tokens) > output_pos + 1:
485-
unquoted_path = utils.strip_quotes(tokens[output_pos + 1])
498+
if len(tokens) > output_index + 1:
499+
unquoted_path = utils.strip_quotes(tokens[output_index + 1])
486500
output_to = os.path.expanduser(unquoted_path)
487501

488502
# remove all the tokens after the output redirect
489-
tokens = tokens[:output_pos]
490-
except ValueError:
491-
pass
492-
493-
try:
494-
output_pos = tokens.index(constants.REDIRECTION_APPEND)
495-
output = constants.REDIRECTION_APPEND
496-
497-
# Check if we are redirecting to a file
498-
if len(tokens) > output_pos + 1:
499-
unquoted_path = utils.strip_quotes(tokens[output_pos + 1])
500-
output_to = os.path.expanduser(unquoted_path)
501-
502-
# remove all tokens after the output redirect
503-
tokens = tokens[:output_pos]
504-
except ValueError:
505-
pass
503+
tokens = tokens[:output_index]
506504

507505
if terminator:
508506
# whatever is left is the suffix

tests/conftest.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,17 @@
7777
-o, --output-file FILE
7878
output commands to a script file, implies -s
7979
-t, --transcript TRANSCRIPT
80-
output commands and results to a transcript file, implies -s
80+
output commands and results to a transcript file,
81+
implies -s
8182
-c, --clear clear all history
8283
8384
formatting:
84-
-s, --script output commands in script format, i.e. without command numbers
85-
-x, --expanded output expanded commands instead of entered command
86-
-v, --verbose display history and include expanded commands if they differ from the typed command
85+
-s, --script output commands in script format, i.e. without command
86+
numbers
87+
-x, --expanded output fully parsed commands with any aliases and
88+
macros expanded, instead of typed commands
89+
-v, --verbose display history and include expanded commands if they
90+
differ from the typed command
8791
8892
"""
8993

0 commit comments

Comments
 (0)