A lot of scripts read configuration data by sourcing other scripts which are disguised as key/value config files, and I don't even need to explain why that's a bad idea. The reason they do this is because its generally the path of least resistance. Even some software published by freedesktop (specifically xdg-user-dir(1)) does this.
kv(1) would offer a more robust way of doing this by allowing key/value files of a specified format to be queried and modified with simple one-liners.
Invocation
The program would be invoked roughly like this:
kv set|get FILE [KEY[=VALUE]...] [OPTION...]
The program would have two modes of operation. set would change values in the file, and get would retrieve values from the file. Following the mode would be the file to operate on, and then a list of key/value pairs. Specifying the value of a pair in get mode would return that value (as a default) if the pair was not found within the file. Not specifying the value of a pair in set mode would delete that pair from the file.
getting a pair would cause the program to output the value of that pair to stdout.
FILE could be specified as -, which would cause the program to read from stdin. set mode could still be used in this scenario in conjunction with some option to redirect the output to stdout, another file, etc.
File
The file would be a list of lines, each containing either a key/value pair or a comment. The key would be separated from the value with a = character, where everything before is part of the key and everything after is part of the value.
Caveats
Multiple pairs can be specified. I still haven't decided how these would be output in get mode. Perhaps, since the file is separated line by line, each value could be output on its own line.
A malformed file might specify multiple values for the same key. Perhaps the program could just operate on the first one and ignore the rest.
This might be a better task for the already planned/implemented field-oriented utilities (fop, fis, tex, fit, etc). If it is then tell me and I won't make the program.
## Rationale
A lot of scripts read configuration data by sourcing other scripts which are disguised as key/value config files, and I don't even need to explain why that's a bad idea. The reason they do this is because its generally the path of least resistance. Even some software published by freedesktop (specifically `xdg-user-dir(1)`) does this.
`kv(1)` would offer a more robust way of doing this by allowing key/value files of a specified format to be queried and modified with simple one-liners.
## Invocation
The program would be invoked roughly like this:
`kv set|get FILE [KEY[=VALUE]...] [OPTION...]`
The program would have two modes of operation. `set` would change values in the file, and `get` would retrieve values from the file. Following the mode would be the file to operate on, and then a list of key/value pairs. Specifying the value of a pair in `get` mode would return that value (as a default) if the pair was not found within the file. Not specifying the value of a pair in `set` mode would delete that pair from the file.
`get`ting a pair would cause the program to output the value of that pair to stdout.
FILE could be specified as `-`, which would cause the program to read from stdin. `set` mode could still be used in this scenario in conjunction with some option to redirect the output to stdout, another file, etc.
## File
The file would be a list of lines, each containing either a key/value pair or a comment. The key would be separated from the value with a `=` character, where everything before is part of the key and everything after is part of the value.
## Caveats
Multiple pairs can be specified. I still haven't decided how these would be output in `get` mode. Perhaps, since the file is separated line by line, each value could be output on its own line.
A malformed file might specify multiple values for the same key. Perhaps the program could just operate on the first one and ignore the rest.
This *might* be a better task for the already planned/implemented field-oriented utilities (fop, fis, tex, fit, etc). If it is then tell me and I won't make the program.
config=~/.config/greeter.conf
timeOfDay=`kv get "$config"timeOfDay=morning`name=`kv get "$config"name="$USER"`echo good $timeOfDay, $name.
As for what this could look like in a script:
```sh
config=~/.config/greeter.conf
timeOfDay=`kv get "$config" timeOfDay=morning`
name=`kv get "$config" name="$USER"`
echo good $timeOfDay, $name.
```
I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
ASV (#19) might be better than =. Multiple fields would also be nice, but may be overcomplicating the matter.
The idea is that you can also edit the file by hand
> ASV (#19) might be better than `=`. Multiple fields would also be nice, but may be overcomplicating the matter.
The idea is that you can also edit the file by hand
I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
Perhaps it could be a shell builtin (#8), something like source except for only reading variables?
> I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
Perhaps it could be a shell builtin (#8), something like source except for only reading variables?
I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
Could you elaborate on this?
> I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
Could you elaborate on this?
This would be more idiomatic:
```sh
$ config=~/.config/greeter.conf
$ mm -i "$config"
timeOfDay=morning
name="$USER"
$ mm -i "$config" | fit -d"\n" kv # sets timeOfDay and name
printf 'good %s, %s\n' "$timeOfDay", "$name".
```
[fit(1)](https://git.tebibyte.media/bonsai/harakit/issues/68)
ASV (#19) might be better than =. Multiple fields would also be nice, but may be overcomplicating the matter.
The idea is that you can also edit the file by hand
The assignment symbol makes sense for this, anyway, as that is exactly what it is doing.
> > ASV (#19) might be better than `=`. Multiple fields would also be nice, but may be overcomplicating the matter.
>
> The idea is that you can also edit the file by hand
The assignment symbol makes sense for this, anyway, as that is exactly what it is doing.
$ config=~/.config/greeter.conf
$ mm -i "$config"timeOfDay=morning
name="$USER"
$ mm -i "$config"| fit -d"\n" kv # sets timeOfDay and nameprintf'good %s, %s\n'"$timeOfDay", "$name".
Trying to understand the role of kv in this context. Is it a shell builtin that sets a variable based on a key=value string? Because if so, it may have undesirable effects (setting an internal variable or overriding env variable) unless all variables set by it are prefixed in some way. Also, I don't see how fit(1) could be capable of running a shell builtin within the current shell as if it were a command.
> This would be more idiomatic:
> ```sh
> $ config=~/.config/greeter.conf
> $ mm -i "$config"
> timeOfDay=morning
> name="$USER"
> $ mm -i "$config" | fit -d"\n" kv # sets timeOfDay and name
> printf 'good %s, %s\n' "$timeOfDay", "$name".
> ```
Trying to understand the role of `kv` in this context. Is it a shell builtin that sets a variable based on a `key=value` string? Because if so, it may have undesirable effects (setting an internal variable or overriding env variable) unless all variables set by it are prefixed in some way. Also, I don't see how fit(1) could be capable of running a shell builtin within the current shell as if it were a command.
Setting values in the file could be achieved through manual editing and in scripts by existing (or not yet existing) tools.
In my opinion this kind of defeats the purpose of the tool, the idea was to allow scripts to read and write to flat files to store and recall arbitrary information. In order to be useful I think it would have to at least be capable of formatting an entry given a key and a value.
> Setting values in the file could be achieved through manual editing and in scripts by existing (or not yet existing) tools.
In my opinion this kind of defeats the purpose of the tool, the idea was to allow scripts to read and write to flat files to store and recall arbitrary information. In order to be useful I think it would have to at least be capable of formatting an entry given a key and a value.
$ config=~/.config/greeter.conf
$ mm -i "$config"timeOfDay=morning
name="$USER"
$ mm -i "$config"| fit -d"\n" kv # sets timeOfDay and nameprintf'good %s, %s\n'"$timeOfDay", "$name".
Trying to understand the role of kv in this context. Is it a shell builtin that sets a variable based on a key=value string? Because if so, it may have undesirable effects (setting an internal variable or overriding env variable) unless all variables set by it are prefixed in some way. Also, I don't see how fit(1) could be capable of running a shell builtin within the current shell as if it were a command.
The qi(1) shell is going to have as few builtins as possible, therefore this probably wouldnt be implemented as one. The kv(1) invocation here would simply export variables into the environment, which is what I thought its purpose was from your description.
> > This would be more idiomatic:
> > ```sh
> > $ config=~/.config/greeter.conf
> > $ mm -i "$config"
> > timeOfDay=morning
> > name="$USER"
> > $ mm -i "$config" | fit -d"\n" kv # sets timeOfDay and name
> > printf 'good %s, %s\n' "$timeOfDay", "$name".
> > ```
>
> Trying to understand the role of `kv` in this context. Is it a shell builtin that sets a variable based on a `key=value` string? Because if so, it may have undesirable effects (setting an internal variable or overriding env variable) unless all variables set by it are prefixed in some way. Also, I don't see how fit(1) could be capable of running a shell builtin within the current shell as if it were a command.
The `qi(1)` shell is going to have as few builtins as possible, therefore this probably wouldnt be implemented as one. The `kv(1)` invocation here would simply export variables into the environment, which is what I thought its purpose was from your description.
I see where I misunderstood. The kv(1) command in your original proposal returns the variable value from the store. Altogether, though, I’m starting to wonder what the benefit of this is over having environment variables set in the shell environment.
I see where I misunderstood. The `kv(1)` command in your original proposal *returns* the variable value from the store. Altogether, though, I’m starting to wonder what the benefit of this is over having environment variables set in the shell environment.
I’m starting to wonder what the benefit of this is over having environment variables set in the shell environment.
Configuring things via environment variables is generally very clumsy. Changing a configuration value requires setting the variable(s) in your profile, and logging out and back in again. If you want to access these new values without doing that, you need to manually export the variables in each new shell and/or specify them before running the program which reads them. It's not as simple as changing a line in a file and re-running the program, or changing a value using some CLI/GUI tool. The way environment variables are stored, loaded, and reset needs to be rethought somewhat if they are to be used as a configuration system. Additionally, environment variables are only good for configuration parameters and can't be used as a general data storage/retrieval mechanism.
> I’m starting to wonder what the benefit of this is over having environment variables set in the shell environment.
Configuring things via environment variables is generally very clumsy. Changing a configuration value requires setting the variable(s) in your profile, and logging out and back in again. If you want to access these new values without doing that, you need to manually export the variables in each new shell and/or specify them before running the program which reads them. It's not as simple as changing a line in a file and re-running the program, or changing a value using some CLI/GUI tool. The way environment variables are stored, loaded, and reset needs to be rethought somewhat if they are to be used as a configuration system. Additionally, environment variables are only good for configuration parameters and can't be used as a general data storage/retrieval mechanism.
Configuring things via environment variables is generally very clumsy. Changing a configuration value requires setting the variable(s) in your profile, and logging out and back in again
This is a misuse of the .profile file as it is for login shells only. For configuration data which can be read by non-login shells, .env is the preferred location. This still does require a shell reload but, to quote @trinity, we're working on an ecosystem so we can actually solve these issues (for ourselves). For example, we can make the shell watch the .env-equivalent and reload for any changes.
The way environment variables are stored, loaded, and reset needs to be rethought somewhat if they are to be used as a configuration system. Additionally, environment variables are only good for configuration parameters and can't be used as a general data storage/retrieval mechanism.
Please elaborate.
> Configuring things via environment variables is generally very clumsy. Changing a configuration value requires setting the variable(s) in your profile, and logging out and back in again
This is a misuse of the `.profile` file as it is for login shells only. For configuration data which can be read by non-login shells, `.env` is the preferred location. This still does require a shell reload but, to quote @trinity, [we're working on an ecosystem so we can actually solve these issues (for ourselves).](https://git.tebibyte.media/bonsai/harakit/issues/19#issuecomment-3257) For example, we can make the shell watch the `.env`-equivalent and reload for any changes.
> The way environment variables are stored, loaded, and reset needs to be rethought somewhat if they are to be used as a configuration system. Additionally, environment variables are only good for configuration parameters and can't be used as a general data storage/retrieval mechanism.
Please elaborate.
Well, you half elaborated for me. Watching .env as you described is the kind of "rethinking" I was talking about. As for the general data storage/retrieval mechanism, I was sort of envisioning it, along with directory hierarchies, being used to store and manipulate structured data in a way that can't really be expressed with env variables. I'll list some examples here:
Desktop icons/launchers
Init services
Virtual web hosts/reverse proxying (i.e. nginx and tor)
Of course, these all imply complicated software, and the main consumer of such files would likely not be a shell script. However, ideally, kv(1) and the programs would speak the same language here, and it would be possible to write scripts that manage and interact with these files.
Maybe this would be more useful as some sort of library that kv(1) is a shell interface to.
> Please elaborate
Well, you half elaborated for me. Watching `.env` as you described is the kind of "rethinking" I was talking about. As for the general data storage/retrieval mechanism, I was sort of envisioning it, along with directory hierarchies, being used to store and manipulate structured data in a way that can't really be expressed with env variables. I'll list some examples here:
- Desktop icons/launchers
- Init services
- Virtual web hosts/reverse proxying (i.e. nginx and tor)
Of course, these all imply complicated software, and the main consumer of such files would likely not be a shell script. However, ideally, kv(1) and the programs would speak the same language here, and it would be possible to write scripts that manage and interact with these files.
Maybe this would be more useful as some sort of library that kv(1) is a shell interface to.
Well, you half elaborated for me. Watching .env as you described is the kind of "rethinking" I was talking about. As for the general data storage/retrieval mechanism, I was sort of envisioning it, along with directory hierarchies, being used to store and manipulate structured data in a way that can't really be expressed with env variables. I'll list some examples here:
Desktop icons/launchers
Init services
Virtual web hosts/reverse proxying (i.e. nginx and tor)
Of course, these all imply complicated software, and the main consumer of such files would likely not be a shell script. However, ideally, kv(1) and the programs would speak the same language here, and it would be possible to write scripts that manage and interact with these files.
Maybe this would be more useful as some sort of library that kv(1) is a shell interface to.
This seems more like something you’d build using the harakit and not something to be included in it.
> > Please elaborate
>
> Well, you half elaborated for me. Watching `.env` as you described is the kind of "rethinking" I was talking about. As for the general data storage/retrieval mechanism, I was sort of envisioning it, along with directory hierarchies, being used to store and manipulate structured data in a way that can't really be expressed with env variables. I'll list some examples here:
>
> - Desktop icons/launchers
> - Init services
> - Virtual web hosts/reverse proxying (i.e. nginx and tor)
>
> Of course, these all imply complicated software, and the main consumer of such files would likely not be a shell script. However, ideally, kv(1) and the programs would speak the same language here, and it would be possible to write scripts that manage and interact with these files.
>
> Maybe this would be more useful as some sort of library that kv(1) is a shell interface to.
This seems more like something you’d build *using* the harakit and not something to be included in it.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Rationale
A lot of scripts read configuration data by sourcing other scripts which are disguised as key/value config files, and I don't even need to explain why that's a bad idea. The reason they do this is because its generally the path of least resistance. Even some software published by freedesktop (specifically
xdg-user-dir(1)) does this.kv(1)would offer a more robust way of doing this by allowing key/value files of a specified format to be queried and modified with simple one-liners.Invocation
The program would be invoked roughly like this:
kv set|get FILE [KEY[=VALUE]...] [OPTION...]The program would have two modes of operation.
setwould change values in the file, andgetwould retrieve values from the file. Following the mode would be the file to operate on, and then a list of key/value pairs. Specifying the value of a pair ingetmode would return that value (as a default) if the pair was not found within the file. Not specifying the value of a pair insetmode would delete that pair from the file.getting a pair would cause the program to output the value of that pair to stdout.FILE could be specified as
-, which would cause the program to read from stdin.setmode could still be used in this scenario in conjunction with some option to redirect the output to stdout, another file, etc.File
The file would be a list of lines, each containing either a key/value pair or a comment. The key would be separated from the value with a
=character, where everything before is part of the key and everything after is part of the value.Caveats
Multiple pairs can be specified. I still haven't decided how these would be output in
getmode. Perhaps, since the file is separated line by line, each value could be output on its own line.A malformed file might specify multiple values for the same key. Perhaps the program could just operate on the first one and ignore the rest.
This might be a better task for the already planned/implemented field-oriented utilities (fop, fis, tex, fit, etc). If it is then tell me and I won't make the program.
As for what this could look like in a script:
ASV (#19) might be better than
=. Multiple fields would also be nice, but may be overcomplicating the matter.I definitely think this is a little too high-level to implement here as its own tool. We should aim to support this via other tools in harakit, though.
The idea is that you can also edit the file by hand
Perhaps it could be a shell builtin (#8), something like source except for only reading variables?
Could you elaborate on this?
This would be more idiomatic:
fit(1)
it should be noted that
-d"\n"does not work in POSIX shell as it passes a literal \n to the program. Here, it represents a literal newline.In
qi(1), \n will expand to a literal newline.The assignment symbol makes sense for this, anyway, as that is exactly what it is doing.
Setting values in the file could be achieved through manual editing and in scripts by existing (or not yet existing) tools.
Trying to understand the role of
kvin this context. Is it a shell builtin that sets a variable based on akey=valuestring? Because if so, it may have undesirable effects (setting an internal variable or overriding env variable) unless all variables set by it are prefixed in some way. Also, I don't see how fit(1) could be capable of running a shell builtin within the current shell as if it were a command.In my opinion this kind of defeats the purpose of the tool, the idea was to allow scripts to read and write to flat files to store and recall arbitrary information. In order to be useful I think it would have to at least be capable of formatting an entry given a key and a value.
The
qi(1)shell is going to have as few builtins as possible, therefore this probably wouldnt be implemented as one. Thekv(1)invocation here would simply export variables into the environment, which is what I thought its purpose was from your description.I see where I misunderstood. The
kv(1)command in your original proposal returns the variable value from the store. Altogether, though, I’m starting to wonder what the benefit of this is over having environment variables set in the shell environment.Configuring things via environment variables is generally very clumsy. Changing a configuration value requires setting the variable(s) in your profile, and logging out and back in again. If you want to access these new values without doing that, you need to manually export the variables in each new shell and/or specify them before running the program which reads them. It's not as simple as changing a line in a file and re-running the program, or changing a value using some CLI/GUI tool. The way environment variables are stored, loaded, and reset needs to be rethought somewhat if they are to be used as a configuration system. Additionally, environment variables are only good for configuration parameters and can't be used as a general data storage/retrieval mechanism.
This is a misuse of the
.profilefile as it is for login shells only. For configuration data which can be read by non-login shells,.envis the preferred location. This still does require a shell reload but, to quote @trinity, we're working on an ecosystem so we can actually solve these issues (for ourselves). For example, we can make the shell watch the.env-equivalent and reload for any changes.Please elaborate.
Well, you half elaborated for me. Watching
.envas you described is the kind of "rethinking" I was talking about. As for the general data storage/retrieval mechanism, I was sort of envisioning it, along with directory hierarchies, being used to store and manipulate structured data in a way that can't really be expressed with env variables. I'll list some examples here:Of course, these all imply complicated software, and the main consumer of such files would likely not be a shell script. However, ideally, kv(1) and the programs would speak the same language here, and it would be possible to write scripts that manage and interact with these files.
Maybe this would be more useful as some sort of library that kv(1) is a shell interface to.
This seems more like something you’d build using the harakit and not something to be included in it.
It would be better to read from standard input only and use file redirection.