INI files refuse to die. Samba, PHP, Git, MySQL, half of /etc — they’re everywhere, and editing them from a shell script is annoying enough that people reach for sed, regret it, and then write a much worse bug. gini is the tiny tool I wrote so I could stop doing that.

What it does

gini is a CLI that does four things on INI files:

  • get a key (optionally inside a section)
  • set a key (creating the file or section as needed)
  • del a key
  • delsection to wipe a whole section

That’s all. It uses go-ini under the hood, so quoting, comments, and section parsing follow the conventions that file format actually obeys — instead of whatever your regex thinks it does.

Install

A few options:

# Homebrew
brew tap sgaunet/homebrew-tools
brew install sgaunet/tools/gini

# asdf
asdf plugin-add gini https://github.com/sgaunet/asdf-gini.git
asdf install gini latest

Or grab a binary from the releases page and drop it in /usr/local/bin.

Reading values

The flags are short on purpose because you’ll type them a lot:

  • --i input file
  • --k key
  • --s section (optional)
$ gini get --k key --i tests/test.ini
value

$ gini get --k key2 --i tests/test.ini --s section
value2

If the key doesn’t exist, gini prints nothing and exits with code 0 — which is the right behaviour for shell scripting:

$ gini get --k keyThatDoNotExists --i tests/test.ini
$ echo $?
0

Combine that with [ -z "$(gini get ...)" ] and you get a clean conditional without parsing error output.

Setting values

set takes one extra flag — --v for the value — and a --c flag to create the file if it doesn’t exist:

# Update an existing key
gini set --i config.ini --s database --k host --v db.example.com

# Create the file on first run
gini set --c --i config.ini --s database --k port --v 5432

The --c flag is the small detail that makes gini actually pleasant in provisioning scripts: you don’t need a separate “does the file exist” guard, you just always pass --c and let the tool sort it out.

Deleting

# Drop a single key
gini del --i config.ini --s database --k password

# Wipe an entire section
gini delsection --i config.ini --s legacy

Useful for cleaning up secrets from a checked-in template, or for tearing down a section after a config migration.

Why a dedicated tool

Could you do all this with awk or crudini? Sure. crudini in particular is excellent. gini exists because:

  • It’s a single static Go binary — no Python runtime, no apt dance.
  • The flag surface is intentionally tiny, so I never have to re-read the man page.
  • The non-zero/zero exit code semantics fit the way I write Bash.

Different scratches for different itches.

Where to find it

It’s open source, MIT-licensed, and short enough to read in one sitting. If you spend any time wrangling INI files from scripts, give it a try.