Skip to content

Commit

Permalink
Don't shell-parse REPL shell commands to make redirection etc. work
Browse files Browse the repository at this point in the history
Julia's "shell parsing" (as used for backticks) excplicitly states that output redirection, pipes etc. are not supported via their shell metacharacters. Thus parsing a REPL shell command via the backtick mechanism makes it impossible to redirect output, unless shell quoting has loopholes and lets these metacharacters through (which leads to severe problems if one e.g. wants to quote an already-quoted string).

For example, Julia's shell parsing returns the same result for these two different commands:
   echo '>a'
   echo >a
In both cases, the command ["echo", ">a"] is generated, assuming that the character ">" is not special. It is then impossible to extract the original REPL user's intention from this command. Thus the REPL needs to parse shell commands via `split`, which suffices to determine whether the command is `cd`. Everything else is left to the shell.
  • Loading branch information
eschnett committed Sep 18, 2015
1 parent 2ab5416 commit bf8ecc9
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 12 deletions.
6 changes: 2 additions & 4 deletions base/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -727,11 +727,9 @@ function setup_interface(repl::LineEditREPL; hascolor = repl.hascolor, extra_rep
(repl.envcolors ? Base.input_color : repl.input_color) : "",
keymap_func_data = repl,
complete = ShellCompletionProvider(repl),
# Transform "foo bar baz" into `foo bar baz` (shell quoting)
# and pass into Base.repl_cmd for processing (handles `ls` and `cd`
# special)
# Pass into Base.repl_cmd for processing (handles `cd` special)
on_done = respond(repl, julia_prompt) do line
Expr(:call, :(Base.repl_cmd), macroexpand(Expr(:macrocall, symbol("@cmd"),line)), outstream(repl))
Base.repl_cmd(line, outstream(repl))
end)

################################# Stage II #############################
Expand Down
22 changes: 14 additions & 8 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ exit(n) = ccall(:jl_exit, Void, (Int32,), n)
exit() = exit(0)
quit() = exit()

function repl_cmd(cmd, out)
function repl_cmd(line, out)
shell = shell_split(get(ENV,"JULIA_SHELL",get(ENV,"SHELL","/bin/sh")))
# Note that we can't support the fish shell due to its lack of subshells
# See this for details: https://github.com/JuliaLang/julia/issues/4918
Expand All @@ -49,29 +49,35 @@ function repl_cmd(cmd, out)
shell = "/bin/sh"
end

if isempty(cmd.exec)
cmds = split(line)
if isempty(cmds)
throw(ArgumentError("no cmd to execute"))
elseif cmd.exec[1] == "cd"
elseif cmds[1] == "cd"
new_oldpwd = pwd()
if length(cmd.exec) > 2
if length(cmds) > 2
throw(ArgumentError("cd method only takes one argument"))
elseif length(cmd.exec) == 2
dir = cmd.exec[2]
elseif length(cmds) == 2
dir = cmds[2]
if dir == "-"
if !haskey(ENV, "OLDPWD")
error("cd: OLDPWD not set")
end
cd(ENV["OLDPWD"])
else
cd(@windows? dir : readchomp(`$shell -c "echo $(shell_escape(dir))"`))
cmd = "echo $dir"
unixcmd = `$shell -c $cmd`
cd(@windows? dir : readchomp(unixcmd))
end
else
cd()
end
ENV["OLDPWD"] = new_oldpwd
println(out, pwd())
else
run(ignorestatus(@windows? cmd : (isa(STDIN, TTY) ? `$shell -i -c "($(shell_escape(cmd))) && true"` : `$shell -c "($(shell_escape(cmd))) && true"`)))
ttyflag = isa(STDIN, TTY) ? "-i" : ""
unixcmd = `$shell $ttyflag -c $line`
wincmd = Cmd(Vector{ByteString}(shell_split(line)))
run(ignorestatus(@windows? wincmd : unixcmd))
end
nothing
end
Expand Down

0 comments on commit bf8ecc9

Please sign in to comment.