bash - print env vars in the order they were set - linux

This question pertains to the bash shell
First off, I know how to look at the env vars that are currently set.
I want to know how to list the currently set environment variables in the order they were set. Kind of like "ls -lt" but for env vars.
Is this possible?
EDIT: many were asking why I need this.
I do a lot of debugging, code porting, fixing etc. It requires me to experiment with third party codes that are not always well written. During the process of getting to a successful build, I might need to set, overwrite some env vars. I am pretty good at documenting what I am doing so I can retrace my steps. But sometimes I forget or miss to record my steps.
For very good reasons, our env has a ton of env vars.
I can capture the entire env vars at that moment, but that doesnt help me much. If bash had a way to list env vars in the order they were set, I can clearly identify what I had set.
Also, I agree that there is no reason for bash to track this. But I was hoping it has an internal stack of env vars, which automatically is ordered as last-in-first-out. But I guess that was just too optimistic to expect.
thanks to everyone.

As #pmos suggested in a comment, you might be able to hack some shell function that would manually track when you export something, but the shell itself cannot do this. Here's why. Export makes a name available to the environment. That is only meaningful to the exec*e family of functions. In other words, export is really only meaningful to new processes following the standard fork/exec pattern. But this also means the data structure holding the exported names is not up to the shell, but POSIX C. Here's a fragment of documentation about exec environments:
The argument envp is an array of character pointers to null-terminated strings. These strings shall constitute the environment for the new process image. The envp array is terminated by a null pointer.
and
extern char **environ; is initialized as a pointer to an array of character pointers to the environment strings.
It might seem reasonable to assume that processes add strings to the environment in order, but it doesn't really seem to work that way in fact, and POSIX systems being as complex as they are, it's not surprising they do a lot of setting, resetting and unsetting.
Despite your question focusing on environment variables, your phrasing makes me think you're also interested in tracking when variables get set, which is different from when they get exported. That actually is entirely the shell's problem, but alas, bash (at least) seems not to track this either.
set seems to display the names in alphabetical order. I can't even figure out what ordering the external env command displays them in.

Related

Does "strings" against a binary list all usable variables?

I've had a request from a vendor to set a specific environment variable against their software. I'm currently awaiting an explanation of what this actually does. However, I decided to check to see exactly what environment variables were available within the binary using "strings" (on Solaris in this case). It doesn't list the one that they're talking about though.
I think this means that the setting they're asking for isn't actually picked up in any way by the binary mentioned (or any of that vendor's binaries - I checked through the lot of them). However, I'm unsure and can't find an answer to whether running "strings" against a compiled binary will list all of the variables that it can pick up and use from the OS.
Can anyone help to confirm this?
Thanks in advance.
The fact that the variable name does not appear as a readable string in the binary does not guarantee that the program does not get its value. The environment variable name may, for example, be constructed at runtime by concatenating substrings.

How to use non-static node variables in puppet?

In puppet, I'd like to set a variable on a node (let's say {'acts_as_balancer' => 0}, and then run a script to change that variable to some other (now say {'acts_as_balancer' => 1}). So far I've seen only variables being used as constants in Puppet. What is the way to set variables as non-constants, on nodes?
Variables are (supposed to be) immutable, so you need to do something else, and it really depends on what you are actually trying to achieve.
If you want to run a script that will change the variables on the puppetmaster, then you can just use Hiera and have the script write the proper YAML files. You can also use the generate command, but you will have to be really careful with this.
But you make it sound like you would like to do it during catalog compilation. This is a bad idea at best, as you will almost certainly have to rely on a solution that is parse order dependent.

Securing a workspace variable

Maybe you have come past the following situation. You're working and you start to run one script after another and then suddenly realize you've changed the value of a variable you are interested in. Apart from making a backup of the workspace, is there no other way to protect the variables?
Is there a way to select individual variables in the workspace that you're going to protect?
Apart from seeing the command history register, is there a history register of the different values that have been given to one particular variable?
Running scripts in sequence is a recipe for disaster. If possible, try turning those scripts into functions. This will naturally do away with the problems of overwriting variables you are running into, since variables inside functions are local to those functions whereas variables in scripts are local to the workspace -- and thus easily accessed/overwritten by separate scripts (often unintentionally, especially if you use variable names like "result").
I also agree that writing functions can be helpful in this situation. If however you are manipulating very large data sets then you need to be careful to write your code in a form which doesn't make multiple copies of variables within your functions or you may run into memory shortage problems.
No, there is no workspace history. I would say, if you run into that problem that you described, you should consider changing your programming style.
I would suggest you:
put that much code or information in your script, so you can start from an empty workspace to fulfill a task. For that reason I always put clear all at the start of my main file.
If it's getting too complex, consider calling functions. If you need values that are generated by another script or function, rewrite that script to become a function and call it in your main file or save the variables. Loading variables is absolutely okay. But running scripts in sequence leads to disaster as mentioned by marciovm.

Can a LabVIEW VI tell whether one of its output terminals is wired?

In LabVIEW, is it possible to tell from within a VI whether an output terminal is wired in the calling VI? Obviously, this would depend on the calling VI, but perhaps there is some way to find the answer for the current invocation of a VI.
In C terms, this would be like defining a function that takes arguments which are pointers to where to store output parameters, but will accept NULL if the caller is not interested in that parameter.
As it was said you can't do this in the natural way, but there's a workaround using data value references (requires LV 2009). It is the same idea of giving a NULL pointer to an output argument. The result is given in input as a data value reference (which is the pointer), and checked for Not a Reference by the SubVI. If it is null, do nothing.
Here is the SubVI (case true does nothing of course):
And here is the calling VI:
Images are VI snippets so you can drag and drop on a diagram to get the code.
I'd suggest you're going about this the wrong way. If the compiler is not smart enough to avoid the calculation on its own, make two versions of this VI. One that does the expensive calculation, one that does not. Then make a polymorphic VI that will allow you to switch between them. You already know at design time which version you want (because you're either wiring the output terminal or not), so just use the correct version of the polymorphic VI.
Alternatively, pass in a variable that switches on or off a Case statement for the expensive section of your calculation.
Like Underflow said, the basic answer is no.
You can have a look here to get the what is probably the most official and detailed answer which will ever be provided by NI.
Extending your analogy, you can do this in LV, except LV doesn't have the concept of null that C does. You can see an example of this here.
Note that the code in the link Underflow provided will not work in an executable, because the diagrams are stripped by default when building an EXE and because the RTE does not support some of properties and methods used there.
Sorry, I see I misunderstood the question. I thought you were asking about an input, so the idea I suggested does not apply. The restrictions I pointed do apply, though.
Why do you want to do this? There might be another solution.
Generally, no.
It is possible to do a static analysis on the code using the "scripting" features. This would require pulling the calling hierarchy, and tracking the wire references.
Pulling together a trial of this, there are some difficulties. Multiple identical sub-vi's on the same diagram are difficult to distinguish. Also, terminal references appear to be accessible mostly by name, which can lead to some collisions with identically named terminals of other vi's.
NI has done a bit of work on a variation of this problem; check out this.
In general, the LV compiler optimizes the machine code in such a way that unused code is not even built into the executable.
This does not apply to subVIs (because there's no way of knowing that you won't try to use the value of the indicators somehow, although LV could do it if it removes the FP when building an executable, and possibly does), but there is one way you can get it to apply to a subVI - inline the subVI, which should allow the compiler to see the outputs aren't used. You can also set its priority to subroutine, which will possibly also do this, but I wouldn't recommend that.
Officially, in-lining is only available in LV 2010, but there are ways of accessing the private VI property in older versions. I wouldn't recommend it, though, and it's likely that 2010 has some optimizations in this area that older versions did not.
P.S. In general, the details of the compiling process are not exposed and vary between LV versions as NI tweaks the compiler. The whole process is supposed to have been given a major upgrade in LV 2010 and there should be a webcast on NI's site with some of the details.

How join 2 variable in shell script?

INPUT=10
OUTPUT_IN=20
KEYWORD="IN"
echo $OUTPUT_"$KEYWORD"
It should display 20
Mainly I am looking to generate the variable name OUTPUT_IN
How to resolve this?
You can use indirection in Bash like this:
INPUT=10
OUTPUT_IN=20
KEYWORD="IN"
var="OUTPUT_$KEYWORD"
echo "${!var}"
However, you should probably use an array or some other method to do what you want. From BashFAQ/006:
Putting variable names or any other bash syntax inside parameters is generally a bad idea. It violates the separation between code and data; and as such brings you on a slippery slope toward bugs, security issues etc. Even when you know you "got it right", because you "know and understand exactly what you're doing", bugs happen to all of us and it pays to respect separation practices to minimize the extent of damage they can have.
Aside from that, it also makes your code non-obvious and non-transparent.
Normally, in bash scripting, you won't need indirect references at all. Generally, people look at this for a solution when they don't understand or know about Bash Arrays or haven't fully considered other Bash features such as functions.
And you should avoid using eval if at all possible. From BashFAQ/048:
If the variable contains a shell command, the shell might run that command, whether you wanted it to or not. This can lead to unexpected results, especially when variables can be read from untrusted sources (like users or user-created files).
Bash 4 has associative arrays which would allow you to do this:
array[in]=10
array[out]=20
index="out"
echo "${array[$index]}"
eval newvar=\$$varname
Source: Advanced Bash-Scripting Guide, Indirect References

Resources