mirror of
https://github.com/samsonjs/csc360-a1-shell.git
synced 2026-03-25 08:45:52 +00:00
Respect escaped command substitution
This commit is contained in:
parent
6a5dec6afc
commit
7cddb9393d
3 changed files with 39 additions and 11 deletions
|
|
@ -113,12 +113,7 @@ module Shell
|
||||||
state = :unquoted if c == "\""
|
state = :unquoted if c == "\""
|
||||||
|
|
||||||
when :double_quoted_escape
|
when :double_quoted_escape
|
||||||
case c
|
command << "\\"
|
||||||
when "\"", "\\", "$", "`"
|
|
||||||
# no-op
|
|
||||||
else
|
|
||||||
command << "\\" # POSIX behaviour, backslash remains
|
|
||||||
end
|
|
||||||
command << c
|
command << c
|
||||||
state = :double_quoted
|
state = :double_quoted
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ module Shell
|
||||||
ENV_VAR_REGEX = /\$(?:\{([^}]+)\}|(\w+)\b)/
|
ENV_VAR_REGEX = /\$(?:\{([^}]+)\}|(\w+)\b)/
|
||||||
DEFAULT_VAR_REGEX = /\A(\w+):-([\s\S]*)\z/
|
DEFAULT_VAR_REGEX = /\A(\w+):-([\s\S]*)\z/
|
||||||
ESCAPED_DOLLAR = "\u0001"
|
ESCAPED_DOLLAR = "\u0001"
|
||||||
|
ESCAPED_BACKTICK = "\u0002"
|
||||||
|
|
||||||
# Splits the given line into multiple words, performing the following transformations:
|
# Splits the given line into multiple words, performing the following transformations:
|
||||||
#
|
#
|
||||||
|
|
@ -18,7 +19,9 @@ module Shell
|
||||||
substituted_line = expand_command_substitution(protected_line)
|
substituted_line = expand_command_substitution(protected_line)
|
||||||
shellsplit(substituted_line)
|
shellsplit(substituted_line)
|
||||||
.map do |word|
|
.map do |word|
|
||||||
expand_variables(word).tr(ESCAPED_DOLLAR, "$")
|
expand_variables(word)
|
||||||
|
.tr(ESCAPED_DOLLAR, "$")
|
||||||
|
.tr(ESCAPED_BACKTICK, "`")
|
||||||
# TODO: expand globs
|
# TODO: expand globs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -138,6 +141,23 @@ module Shell
|
||||||
output << c
|
output << c
|
||||||
i += 1
|
i += 1
|
||||||
end
|
end
|
||||||
|
when "\\"
|
||||||
|
if i + 1 < line.length
|
||||||
|
escaped = line[i + 1]
|
||||||
|
if escaped == "$"
|
||||||
|
output << ESCAPED_DOLLAR
|
||||||
|
i += 2
|
||||||
|
elsif escaped == "`"
|
||||||
|
output << ESCAPED_BACKTICK
|
||||||
|
i += 2
|
||||||
|
else
|
||||||
|
output << c
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
output << c
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
else
|
else
|
||||||
output << c
|
output << c
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -154,6 +174,20 @@ module Shell
|
||||||
output << c
|
output << c
|
||||||
state = :unquoted
|
state = :unquoted
|
||||||
i += 1
|
i += 1
|
||||||
|
when "\\"
|
||||||
|
if i + 1 < line.length
|
||||||
|
escaped = line[i + 1]
|
||||||
|
if escaped == "$" || escaped == "`" || escaped == "\\" || escaped == "\""
|
||||||
|
output << (escaped == "$" ? ESCAPED_DOLLAR : (escaped == "`" ? ESCAPED_BACKTICK : escaped))
|
||||||
|
else
|
||||||
|
output << "\\"
|
||||||
|
output << escaped
|
||||||
|
end
|
||||||
|
i += 2
|
||||||
|
else
|
||||||
|
output << c
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
when "`"
|
when "`"
|
||||||
cmd, i = read_backtick(line, i + 1)
|
cmd, i = read_backtick(line, i + 1)
|
||||||
output << run_command_substitution(cmd)
|
output << run_command_substitution(cmd)
|
||||||
|
|
@ -263,5 +297,6 @@ module Shell
|
||||||
end
|
end
|
||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -99,13 +99,11 @@ class ShellTest < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_does_not_expand_escaped_command_substitution_dollar_paren_in_double_quotes
|
def test_does_not_expand_escaped_command_substitution_dollar_paren_in_double_quotes
|
||||||
skip "escape handling for command substitution in double quotes is limited"
|
assert_equal "$(echo hi)", %x(#{A1_PATH} -c 'echo "\\$(echo hi)"').chomp
|
||||||
assert_equal "$(echo hi)", `#{A1_PATH} -c 'echo "\\$(echo hi)"'`.chomp
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_does_not_expand_escaped_command_substitution_backticks_in_double_quotes
|
def test_does_not_expand_escaped_command_substitution_backticks_in_double_quotes
|
||||||
skip "escape handling for command substitution in double quotes is limited"
|
assert_equal "`echo hi`", %x(#{A1_PATH} -c 'echo "\\`echo hi\\`"').chomp
|
||||||
assert_equal "`echo hi`", %x(#{A1_PATH} -c "echo \"\\`echo hi\\`\"").chomp
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue