# Best practice for script with ARGS that can also be run with \`include\`

**URL:** https://discourse.julialang.org/t/best-practice-for-script-with-args-that-can-also-be-run-with-include/74435
**Category:** General Usage
**Tags:** question, workflow, code-organization
**Created:** [January 11, 2022, 9:31pm UTC](https://discourse.julialang.org/t/best-practice-for-script-with-args-that-can-also-be-run-with-include/74435 "2022-01-11T21:31:22Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [January 11, 2022, 9:31pm UTC](https://discourse.julialang.org/t/best-practice-for-script-with-args-that-can-also-be-run-with-include/74435/1 "2022-01-11T21:31:22Z")

</div>

I’m trying to figure out a good pattern for writing scripts that take command line arguments, and that are easy to run both from the shell (`julia script.jl`), and from inside the REPL/another Julia script (via `include`). The latter option is primarily to reduce the compilation overhead from running multiple scripts, or the same script with different arguments.

The best I’ve come up with so far is to make `script.jl` look like this:

```julia
module TestProg

function main(args=ARGS)
    @show args
end

end

_progmod = TestProg
if abspath(PROGRAM_FILE) == @ __FILE__
    _progmod.main()
end

```

In order to run this programmatically from another script `driver.jl`, I’d use something like

```julia
function run(script, args...; mod=:_progmod, main=:main)
    include(script)
    @eval $mod.$main($args)
end

run("script.jl", "A", "B")

```

The `_progmod` is just to establish a standard across all my scripts, so I don’t have to look at the source code of each script for the module name (`run("script.jl", "A", "B", mod=:TestProg)` would also work, if `_progmod` wasn’t defined).

In the REPL, I would do

```julia
julia> include("script.jl")
julia> TestProg.main(["A", "B"])

```

Does this look like a good pattern? Does anybody have any idea on how to improve on this?

The one small drawback is that running the `run` helper function multiple times from within the same julia session shows a `WARNING: replacing module TestProg`. I don’t think there’s any actual problem with the reloading, though.

---

<div class="post-metadata">

### Author: ![jbrea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbrea/32/3879_2.png) [@jbrea](https://discourse.julialang.org/u/jbrea)
#### Post date: [January 12, 2022, 9:09am UTC](https://discourse.julialang.org/t/best-practice-for-script-with-args-that-can-also-be-run-with-include/74435/2 "2022-01-12T09:09:34Z")

</div>

Why not just manipulate `ARGS`?

Something like `script.jl`:

```julia
module TestProg

function main(args=ARGS)
    @show args
end

end

TestProg.main()

```

and `driver.jl`

```julia
setargs!(ARGS, args...) = (empty!(ARGS); append!(ARGS, args))
function run(script, args...)
    setargs!(ARGS, args...)
    include(script)
end

run("script.jl", "A", "B")

```

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [January 12, 2022, 12:58pm UTC](https://discourse.julialang.org/t/best-practice-for-script-with-args-that-can-also-be-run-with-include/74435/3 "2022-01-12T12:58:01Z")

</div>

> [@goerz](#):
>
> Does this look like a good pattern?

In the long run, it’s far better to write functions with arguments as parameters than scripts.with global arguments for any code you want to re-use. (You can still use scripts — just put the script in a short file that uses/includes your other code and passes `ARGS` as function parameters.)

See also [Best practise: organising code in Julia - #2 by stevengj](https://discourse.julialang.org/t/best-practise-organising-code-in-julia/74362/2) and [Best practise: organising code in Julia - #4 by stevengj](https://discourse.julialang.org/t/best-practise-organising-code-in-julia/74362/4)

---

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [January 14, 2022, 4:11am UTC](https://discourse.julialang.org/t/best-practice-for-script-with-args-that-can-also-be-run-with-include/74435/4 "2022-01-14T04:11:02Z")

</div>

Oh, I agree 100%! This is for those short top-level scripts, e.g., [this one](https://github.com/goerz-research/2022-01_Rydberg_Krotov_Spectral_Constraints/blob/a2a8654cd00c6c3db79b982d045bfd321b8249d0/scripts/2022-01-13_constrained_stage1.jl). A more fleshed-out “driver” to run that script to programmatically is [here](https://github.com/goerz-research/2022-01_Rydberg_Krotov_Spectral_Constraints/blob/a2a8654cd00c6c3db79b982d045bfd321b8249d0/src/makerules.jl#L42-L69), as part of a `make`-like system to programmatically run all the scripts in the project, cf. [Julia-based Makefile replacement for research workflows](https://discourse.julialang.org/t/julia-based-makefile-replacement-for-research-workflows/74368). Of course, I still want to be able to run the script either from the command line with normal arguments, or from the REPL or a notebook, for playing around with different parameters.
