# Providing variable length args to \`run\` command?

**URL:** <https://discourse.julialang.org/t/providing-variable-length-args-to-run-command/51882>\
**Category:** General Usage\
**Created:** [December 15, 2020, 4:50pm UTC](https://discourse.julialang.org/t/providing-variable-length-args-to-run-command/51882 "2020-12-15T16:50:48Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [December 15, 2020, 4:50pm UTC](https://discourse.julialang.org/t/providing-variable-length-args-to-run-command/51882/1 "2020-12-15T16:50:48Z")

</div>

Hey all. I’m having some trouble using the `run` command with a variable number of args to the thing I’m trying to `run`. For context, I’m playing around with some ways to very directly interact with Gnuplot scripts. I’m aware that there are several existing interfaces and I’m not trying to do anything serious here, but now I want to know how to do this correctly. Here’s my little snippet:

```julia
using DelimitedFiles

# Default kwargs. Probably eventually needs to be a dict of dicts, with the
# outer index being the "scriptname" arg, like :lineplot used in ARGORDER below.
const DEF = Dict(:terminal=>"pngcairo", :xsize=>500, :ysize=>500, 
                 :font=>"Verdana", :fontsize=>10, :outputname=>"output.png",
                :tmpfile=>nothing)

# Could use this to automatically splat out the args in the right order without
# having to touch the plot function internals.
const ARGORDER = Dict(:lineplot=>(:terminal, :xsize, :ysize, :font, :fontsize, :outputname))

# Common list of errors.
const ERRORS = Dict(:argerror=>ArgumentError("Here's a helpful error message."))

function plot(x, y; scriptname=:lineplot, kwargs...)
  args = merge(DEF, kwargs) # TODO: check that no kwarg is silently ignored.
  scriptfile = string(scriptname, ".gp")
  tmpfile = isnothing(args[:tmpfile]) ? mktemp()[1] : args[:tmpfile]
  writedlm(tmpfile, hcat(x,y), ' ')
  if haskey(ARGORDER, scriptname)
    # not sure if string conversion is necessary, but just trying to cover all my bases.
    gp_args = map(x->string(args[x]), ARGORDER[scriptname])
  else
    haskey(args, :argorder) || throw(ERRORS[:argerror])
    gp_args = map(x->string(args[x]), args[:argorder])
  end
  # (i): What is the correct way to supply these args? The help seems to suggest
  # that this is a fine way to do it, but clearly I'm misreading ?run.
  # run(`gnuplot -c $scriptfile $tmpfile`, gp_args...)
  #
  # (ii): Alternatively, I have tried this, but this leaves an extra set of
  # backticks, so I somehow am not splatting these args correctly.
  # run(`gnuplot -c $scriptfile $tmpfile $(map(x->string(x, " "), gp_args)...)`)
  run(`xdg-open $(args[:outputname])`)
end

```

And the corresponding `lineplot.gp` file is

```julia
set terminal ARG2 size ARG3,ARG4 enhanced font 'ARG5,ARG6'

set autoscale xfix
set autoscale yfix

set output ARG7
plot ARG1 using 1:2 with linespoints pointtype 6 notitle
unset output

```

The big comment chunk of the first snippet show two things that I’ve tried to do to splat the args provided by `ARGORDER[:lineplot]` into the `run` command, but I am clearly both misinterpreting what `args...` means in the help provided by `?run` (attempt i) AND not understanding how to properly splat in a string interpolation-type thing for (attempt ii).

here’s an example call that should (at least on linux) work once these args get parsed properly:

```julia
plot(1:10, map(abs2, 1:10))

```

If anybody has pointers, I would really appreciate it. Thanks!

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [December 16, 2020, 11:53am UTC](https://discourse.julialang.org/t/providing-variable-length-args-to-run-command/51882/2 "2020-12-16T11:53:06Z")

</div>

You can inspect the command without executing it:

```julia
julia> scriptfile = "lineplot.gp";

julia> tmpfile = "/tmp/jl_XXXXXX";

julia> gp_args = ("pngcairo", "500", "500", "Verdana", "10", "output.png");

julia> cmd = `gnuplot -c $scriptfile $tmpfile $(map(x->string(x, " "), gp_args)...)`
`gnuplot -c lineplot.gp /tmp/jl_XXXXXX 'pngcairo 500 500 Verdana 10 output.png '`

```

Not good: many values will be passed to gnuplot as a single parameter: `'pngcairo 500 500 Verdana 10 output.png '`

What you want is simply:

```julia
julia> cmd = `gnuplot -c $scriptfile $tmpfile $gp_args`
`gnuplot -c lineplot.gp /tmp/jl_XXXXXX pngcairo 500 500 Verdana 10 output.png`

```

This works because a collection (here `gp_args`) will be interpolated as a list of command parameters. See [the documentation](https://docs.julialang.org/en/v1/manual/running-external-programs/#command-interpolation) for details and examples.

Your first idea `run(`gnuplot -c $scriptfile $tmpfile`, gp_args...)` doesn’t work because command arguments must be part of the command object. It’s true that `run` accepts additional arguments but they are unrelated (the documentation could be improved in this regard).

Your second idea is… interesting 🙂 It’s basically doing this:

```julia
julia> `echo $(("a", "b")...)`
`echo ab`

```

What does it mean to splat values in `$(...)`? I’m not sure how this works… And the result is different from

```julia
julia> `echo $("a", "b")`
`echo a b`

```

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [December 16, 2020, 2:58pm UTC](https://discourse.julialang.org/t/providing-variable-length-args-to-run-command/51882/3 "2020-12-16T14:58:33Z")

</div>

My hero. Thanks so much for the explanation and doc links, which of course do provide examples of exactly what I wanted to do. Oof. I always think that I googled the right words and ended up on the right docs, but here we are. Thanks again!
