0

I have a certain value that a bunch of scripts/functions I run on my machine need access to, and it changes frequently. For context, it's the git tag of the current commit deployed to production of the primary app we work on, but that's not important. I've been automating it by setting it as a local variable within the context of my current shell, which has been nice, but any other shells I have open cannot access it. This is unfortunate because I often have multiple shells open and want this variable in all of them.

What would be the best way to pass this value around where every open shell can access it? I looked into setting it as an environment variable, but changing an environment variable does not affect its value in already open shells so that wouldn't work. And I could obviously update it in my .bashrc but that would require re-running a source command in every open shell and I'm lazy. What is the best way to share a value between Bash shells?

Tom Warner
  • 3,193
  • 3
  • 17
  • 24
  • "Best way", "best practice", &c are generally broad and opinion-based, since what's "best" depends on priorities/requirements/use-case details. Someone concerned about a high-concurrency application will have _very_ different concerns from someone who just wants to persist a value between runs but can tolerate that value being lost in the event of an error. – Charles Duffy Aug 02 '23 at 20:31
  • (also interesting are transactional cases, where you can need an atomic check-and-set operation: "if the original value is 2, then save the new value of 4, otherwise return an error so we know we need to reread the old value and recalculate the new value"; obvs., this depends very much on the details of the use case and its context) – Charles Duffy Aug 02 '23 at 21:16
  • How about storing the value in a property file, which can be accessed from several processes? When writing the file, you need to do some locking, to avoid a race condition if the file is updated from several processes simultaneously. Also, the processes reading this file, need to be aware that the value could change any time, so they must not cache it. BTW, you did not specify what OS you are using. Depending on the platform, other possiilities are perhaps also feasible. – user1934428 Aug 03 '23 at 07:06
  • Another idea which comes to my mind: You represent the "variable" by a demon process which offers a socket interface. Whenever a client process needs the content of the variable, it connects via the socket and asks for its value. This assumes that one process is responsible for managing the variable, and the other processes are just reading the value. – user1934428 Aug 03 '23 at 07:08
  • @user1934428 **Redis**, in my answer below, is more or less exactly that daemon process that is contacted via sockets. – Mark Setchell Aug 03 '23 at 07:52

2 Answers2

2

I like Redis for this - it is lightweight, and fast and accessible from any language (Python, bash, Perl, PHP, C/C++, Ruby) and across the network. It supports strings, sets, sorted sets, lists, queues, hashes, atomic integers and so on:

# Set variable to 10
redis-cli set fred 10
OK

# Retrieve variable
redis-cli get fred
"10"
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • 1
    _grumbles about questions so broad that (a huge swath of) tool recommendations are reasonable as answers, and tries to suppress an urge to shill for sqlite_ – Charles Duffy Aug 02 '23 at 21:13
  • This seems better than my idea, which is why I posted the question -- to try to get better ideas. Thanks! – Tom Warner Aug 03 '23 at 12:28
1

So far, the best way I've found is to store the value in a file which all running shells can access, and then write a little wrapper function in my .bashrc that gets/sets the value for any script which needs it. Mine looks something like this:

# With one argument, stores the RC value in a file for scripts to access. With no args, reads it out
rc() {
    if [ $# -eq 1 ]
    then
        echo $1 > /path/to/.rc
    else
        cat /path/to/.rc
    fi  
}

That can then be called by any script which needs to access it with the syntax $(rc), so if for example you just wanted to print it out you could call echo $(rc)

I'm curious to know if there's any better way to do this, though!

Tom Warner
  • 3,193
  • 3
  • 17
  • 24
  • 1
    This is unsafe unless you make careful use of file locking. As it is, one program can try to read the variable at the same time as the other is writing it; depending on how things go it can look completely empty to the reader, since `echo $1 > file` isn't atomic: first it opens the file with `O_TRUNC`, emptying it, and only after that does it write any data. – Charles Duffy Aug 02 '23 at 20:26
  • (`echo $1` also has its own additional bugs; see [I just assigned a variable, but `echo $variable` shows something else!](https://stackoverflow.com/questions/29378566/i-just-assigned-a-variable-but-echo-variable-shows-something-else)) – Charles Duffy Aug 02 '23 at 20:29
  • 1
    ...as a very minimal enhancement that doesn't require file locking but does still suffice to make this safer, _at least_ consider `echo "$1" >/path/to/.rc."$$" && mv /path/to/.rc."$$" /path/to/.rc` -- that way when you open the file for read you get a handle on one specific copy that has fully been written, and if a new write is underway it doesn't change the contents of the copy you're reading. – Charles Duffy Aug 02 '23 at 20:32
  • 1
    (using `$$` has some potential security impact, btw, if `/path/to` is somewhere untrusted accounts have write access -- like `/tmp` -- use `mktemp` instead to generate temporary-file names an attacker can't guess ahead-of-time; this goes to what I was saying about how someone needs to understand context and priorities to weigh what's "best" in any given situation -- optimizing for terseness can cut against security and the inverse). – Charles Duffy Aug 02 '23 at 20:54