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:
geta key (optionally inside a section)seta key (creating the file or section as needed)dela keydelsectionto 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:
--iinput file--kkey--ssection (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
aptdance. - 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
- Source: github.com/sgaunet/gini
- License: MIT
- Releases: Linux, macOS and Windows binaries
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.