Nix/Bash maxi: declaratively configured CLI args to ENV vars tool

I write a lot of Nix+Bash. Sometimes always tempting go out from bash to some real language.

There are many reason, one is parsing command line arguments.

In real languages I decoratively describe my command lines parameters, which at same time can be ENV vars and also can be constants and also can be file. With all nice overrides.

In bash I can use ENV vars, or copy paste some bash script to do parsing of CLI args. But there is no bash tool I found which composes these.

In nix ENV harder to use dynamically, until go --impure. So need to handle CLI args.

So I was thinking.

It there is some tool, which read CLI/ENV parser config from TOML. Than it parses dynamic CLI arguments. And exports all these into ENV vars.

So that bash scripts can use ENV vars, without parsing CLI args in bash.

I was searching such tools - not found.

I feel it will extend further and make Nix+Bash more composable and allow more dynamic nix.

Seems issue more or less unique because of pure for bash shell application.

May be somebody saw similar solutions? Or knows better alternative?

That is not the answer you want, but for me, helped a lot writing scripts with nushell.

https://www.nushell.sh/book/custom_commands.html#documenting-your-command

#!/usr/bin/env nu
def main [
  name: string
  --age (-a): int
  --twice
] {
  if $twice {
    [$name $name $age $age]
  } else {
    [$name $age]
  }
}

# to be called as ./bla.nu subcommand
def "main subcommand" [
  envValue: string = "no donuts for you"
] {
  $env.ENV_VAR = $envValue
  your_command
}

The bad things:

  • They are not stable yet, so break changes are expected.
  • Is not POSIX (no way copy and paste from BASH will work)

The other good things:

  • A lot of sanity
  • JSON, CSV, TOML, YAML parser integrated.
2 Likes

@hugosenari just to clarify, the idea is to write cli shell parsing code in nushell?

like parser code. nushell is middleground - better bash, but not yet ts/py/go/rust(langs in my belt to write shell scripts).

that would nice idea iff nushell will win. resonable pwsh did not won at all (it has idea to use stucture, not pure text for interaction of cli to cli).

what are indicators nushell is great and future proof?

intresting indicator - nushell adopted instead of bash in some prominent project (with nushell stdenv).

Are you trying to avoid parsing in bash, or just writing the code to do it? (There’s something like GitHub - ko1nksm/getoptions: An elegant option/argument parser for shell scripts (full support for bash and all POSIX shells), for example.)

1 Like

Yes, but unless you have created YAYL (YAYL Ain’t YAML Language or Yet Another YAML Language), you don’t need to parse env, args, cfg, only merges them.

Yes, but in DSL, not in a library/framework.

Shell Real Lang Nushell CSS
set/read env
set/read/open/write strings
set/read/open/write structured data
merge structured data
positional args
positional args default value
named args
named args default value
subcommands
help subcommand
invoke other commands

Note:
This is only to your context (CLI+ENV+CFG), Nushell isn’t better than real languages.

It doesn’t need to “win” (surpass Bash), we are in a Nix forum, Nix makes it easy to add random tools to your script/environment. It will cost, and the cost will reduce as more and more people adopts Nushell. On the other side, Nushell could be discontinued. I can’t see it dying so soon. But I’m just guessing.

Anyway Nix is crucial in this context, as you have +80k pkgs, but only if you take Nix for granted, otherwise, whatever tool you find, you have to make sure it is available, adding installation cost to total cost.

1 Like

It has similar stats¹ of older similar² projects.

¹ No, I’m not taking github data as market share, only supporting the idea the Nushell may not die until AI Apocalypse.
² Adding ozmyzsh as a glimpse of Zsh. Zsh vs (Nushell, Fish, Oil) aren’t a fair comparison since they aren’t POSIX, they have more adoption friction.

1 Like

@hugosenari than you. seems reasonable.
imho nushell/powershell seems or me better langs for shells(not js/ts/rust/python), but all lack adoption in clouds now (and not clear why would they will win, i just do no see). my theory that language which transpiles to sh will win (so there are 3 failed dead attempts or some reason - who knows why).

When I am in nix seems getoptions is best for me, as I can use it as package easy. Unfortunately without nix what i see people just copy paste some tons of ugly bash to parse (likely generated) and never up to share with me initial input. Nix fixes sharing generator code and downloading generator seems.

Rust with Serde/Clap integration was interesting form of YAML, but it is half done.

And I wanted just way to make my nix writeShellApplication gluing several other apps be easy CLI configurable (no separate files to provide parameter from users). So later can just rewrite to real app as needed.

1 Like

I’m not sure if it’s of any additional utility in your case (it doesn’t address your CLI parsing question, and I’m not sure how complex what you’re passing through writeShellApplication is), but I also develop GitHub - abathur/resholve: a shell resolver? :) (find and resolve shell script dependencies) for helping square Shell with Nix and package it a bit more fluently.

It can handle both executables and libraries.

Some simpleish examples:

2 Likes

I liked the idea, do you mind sharing the projects links?

I do that with devshell (I had to rewrite it to devenv), that use Nix Modules.

The trick, is that my module expects a list, where the last item is the script, and other items are args definition. Then I glue them all with Nix.

Usage example

{
  nush.hello.en = ["arg" ''
    echo $"hello ($arg)"
  ''];
  nush.hello.pt = ["arg" ''
    echo $"ola ($arg)"
  ''];
  nus.world = ''
    hello en World
    hello pt Mundo
  '';
}

Then I take all the nus and nush to create 1 lib file with all commands/subcommands as functions, and 3 script files to import the lib e call the functions.

I do that with Nushell, because of already mentioned features, but could be done with more work in bash+ getoptions, could also be done without devshell and be created with something like drv-parts to expose flake commands like nix run foo#hello

1 Like