Skip to content

Commit

Permalink
Run: fix escaping params, disable shell features and prevent ahk args…
Browse files Browse the repository at this point in the history
… from spanning multiple parameters

args are now split into params *before* ahk variable substitution.

for example,
```ahk
a = b" "c" > d "
Run, cmd "%a%"
```
would previously excute `cmd "b" "c" > d ""`. Now, it's `cmd "b\" \"c\" > d \""`, so everything is treated literally and shell features like `>` or `&` aren't available anymore. If you need these features, you need to invoke `bash -c '%your_ahk_variable_containing_bash_stuff%'` manually.
  • Loading branch information
phil294 committed Jan 3, 2023
1 parent e5b286d commit 8fd026c
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 12 deletions.
1 change: 1 addition & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10963,6 +10963,7 @@ <h2 class="calibre9"><span class="calibre23">The "Last Found" Window </span></h2
<p class="calibre8"> </p>
<p class="calibre8">While RunWait is in a waiting state, new <a href="#Threads.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">threads</a> can be launched via <a href="#Hotkeys.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">hotkey</a>, <a href="#Menu.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">custom menu item</a>, or <a href="#SetTimer.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">timer</a>.</p>
<p class="calibre8">To launch a program with environment variables set, use <a href="#EnvSet.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">EnvSet</a>. Just prefixing them like `Run, VAR=VALUE cmd` won't work.</p>
<p class="calibre8 x11">Native shell features like redirect (>) or background jobs (&) are not available. Also, ahk variables can not span multiple params. For example, if variable abc contains spaces, then `Run, %abc%` would treat the whole contents of abc as the command path and not split it up. If you really need to work around this, you can invoke the shell directly, e.g. Run, bash -c 'bash code...'.</p>
<p class="calibre8"> </p>
<p class="calibre8"><strong class="calibre14">Related</strong></p>
<p class="calibre8"><a href="#RunAs.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">RunAs</a>, <a href="#Process.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">Process</a>, <a href="#Exit.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">Exit</a></p>
Expand Down
35 changes: 23 additions & 12 deletions src/cmd/misc/run.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,50 @@ class Cmd::Misc::Run < Cmd::Base
def self.max_args; 6 end
@wait = false
# returns either `false` on failure or `i64` exit code or pid, depending on *@wait*.
private def try_execute(line, chdir = nil, stdout = false, stderr = false)
cmd = Process.parse_arguments(line)[0]?
return false, "", "" if ! cmd || ! ::Process.find_executable(cmd)
private def try_execute(thread, line, chdir = nil, stdout = false, stderr = false)
args = Process.parse_arguments(line).map do |arg|
Util::AhkString.parse_string(arg, thread.runner.settings.escape_char) do |var_name_lookup|
thread.get_var(var_name_lookup)
end
end
return false, "", "" if ! args[0]? || ! ::Process.find_executable(args[0])
{% if ! flag?(:release) %}
puts "[debug] runcmd[#{thread.id}]: cmd=#{args[0]} args=#{args[1..]}"
{% end %}
chdir = nil if chdir && chdir.empty?
stdout_m = stdout ? IO::Memory.new : Process::Redirect::Close
stderr_m = stderr ? IO::Memory.new : Process::Redirect::Close
begin
p = Process.new(line, chdir: chdir, shell: true, output: stdout_m, error: stderr_m)
p = Process.new(args[0], args[1..], chdir: chdir, output: stdout_m, error: stderr_m)
rescue e : IO::Error
return false, "", ""
end
ret = @wait ? p.wait.exit_code.to_i64 : p.pid
return ret, stdout_m.to_s, stderr_m.to_s
end
def run(thread, args)
target_raw = @args[0]
target = args[0]
pwd = args[1]?
opt = thread.parse_word_options(args[2]? || "")
output_var_pid = args[3]?
output_stdout = args[4]?
output_stderr = args[5]?

if target.starts_with?("open ")
if target_raw.starts_with?("open ")
target_raw = target_raw[5..]
target = target[5..]
open = true
elsif target.starts_with?("edit ")
elsif target_raw.starts_with?("edit ")
target_raw = target_raw[5..]
target = target[5..]
edit = true
elsif target.starts_with?("explore ")
elsif target_raw.starts_with?("explore ")
target_raw = target_raw[8..]
target = target[8..]
edit = true
elsif target.starts_with?("print ")
elsif target_raw.starts_with?("print ")
target_raw = "lp " + target_raw[6..]
target = "lp " + target[6..]
open = true
else
Expand All @@ -55,7 +67,7 @@ class Cmd::Misc::Run < Cmd::Base
# end

if edit
success, stdout, stderr = try_execute("gtk-launch \"$(xdg-mime query default text/plain)\" '#{target}'", chdir: pwd, stdout: !!output_stdout, stderr: !!output_stderr)
success, stdout, stderr = try_execute(thread, "gtk-launch '#{`xdg-mime query default text/plain`.strip}' '#{target_raw}'", chdir: pwd, stdout: !!output_stdout, stderr: !!output_stderr)
end

thread.runner.display.gui.act do
Expand All @@ -70,12 +82,11 @@ class Cmd::Misc::Run < Cmd::Base
end

if ! success && open
success, stdout, stderr = try_execute(target, chdir: pwd, stdout: !!output_stdout, stderr: !!output_stderr)
success, stdout, stderr = try_execute(thread, target_raw, chdir: pwd, stdout: !!output_stdout, stderr: !!output_stderr)
end

if ! success
path = ::File.expand_path(target)
success = try_execute("xdg-open " + path) && ""
success = try_execute(thread, "xdg-open " + target_raw) && ""
end

if success
Expand Down

0 comments on commit 8fd026c

Please sign in to comment.