Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I am currently parsing through a body of key/value pairs which are read into an array token[0], token[1] respectively. What I need is a means of spawning actual variables with the name of the string within the first variable, and the value contained within the second.
Obviously, pains will be taken to make sure that no exploit code is embedded.
For example:
token[0]="roughVariable"
token[1]="/bin/sh"
... magic happens
$ echo $roughVariable
/bin/sh
The standard indirection methodology appears to be unsuited, and doesn't allow for BOTH a variable variable-name AND a variable value string assignment.
If you have Bash 4, you can use the safer bash technique for indirect variable references: associative arrays. Otherwise, depending on your needs you have available the ${!} bash notation and might have to recur to the use of eval (which is the less preferable, especially if security is a priority).
Associative arrays:
Code:
#!/bin/bash
declare -A token
token[indirect]="roughVariable"
token[roughVariable]="/bin/sh"
echo ${token[${token[indirect]}]}
Regrettably, the site in which I work has not adopted Bash 4 (for reasons too arcane to elucidate here), so "clean" associative array solutions aren't feasible.
The second solution you provided doesn't even touch on the "value" of the key/value pair -- a classic problem in normal bash indirection. You can provide any number of levels of indirection on a variable, but you can't use indirection on both the name AND the value of the string being passed.
The third solution is similarly handicapped; nowhere is the association made between the desired string variable created (here "roughVariable") and the actual value ("/bin/sh" here). It should be noted that the programmer will in all likelihood never see the values "roughVariable" and "/bin/sh" -- they are dynamically defined in the context of an external file not within the programmer's purvey.
I'm still waiting for some bash wizard to poke their head up and puke out a solution that achieves both seemingly impossible things simultaneously.
The second solution you provided doesn't even touch on the "value" of the key/value pair -- a classic problem in normal bash indirection. You can provide any number of levels of indirection on a variable, but you can't use indirection on both the name AND the value of the string being passed.
The third solution is similarly handicapped; nowhere is the association made between the desired string variable created (here "roughVariable") and the actual value ("/bin/sh" here). It should be noted that the programmer will in all likelihood never see the values "roughVariable" and "/bin/sh" -- they are dynamically defined in the context of an external file not within the programmer's purvey.
Oh I just posted examples, not adhering to the exact problem you posted, sorry for that. In the third case I can assure you it's doable, as I explained with eval you pretty much can do any kind of indirection. Here's how to do what you mention:
About the only fly in the ointment is the "eval" (which has a somewhat negative rep amongst the security nazis) -- and there are allegedly ways of using the ${!} and $(expression) notations to work around it. Now it is just a matter of trial and error to find some tortured syntax that will successfully replicate the example you provided without the nasty 'e' word.
Thanks! I'm not quite over the finish line yet, but I can smell victory from where I'm standing.
In terms of the general concept, I'd use a Perl hash instead where
$hash{$key} = $value
and both $key & $value can be strings or nums or just about anything, and you can have an indefinite num of entries in the hash.
I'd also point out that although you can indeed do $$val in Perl, its definitely not recommended as best practice.
Now we're talking! The latest solution will pass muster with the security Nazis, hands-down. I'd read in some of the more arcane "admin" sites about bash tricks of this sort, and hadn't quite had a chance to invest the time required to dig it out.
As to the "better" solution in Perl: yes, Perl is better (in every way) than shell-script. No question. The fact that the less-than-sanctioned $$x construct is one way to handle the issue shouldn't be taken as a negative -- the language also sports associative arrays, referenced associative arrays, arrays of hashes (my go-to solution for almost everything) and hashes of arrays (not-so-much), to name only a few of the more popular methods.
However, the problem I'm working with at present is a mish-mash of Perl and bash scripts; whenever something changes in either environment the whole production stream crashes to a halt. For that reason they've locked down both to positively antiquated versions. My reasoning is that if solid, testable solutions can be derived in BOTH spaces (using only the pure bash, or only the pure Perl code), we can start upgrading them once again to circumvent known problems.
Besides, I'm an artiste -- mixing umpty-ump languages to yield a business solution is simply not kosher. If you're not good enough to render a bullet-proof solution in any one language (given one platform, one problem), you shouldn't be using it. Alternatively, you should be working in forestry or interpretive dance instead of writing code.
Actually, that was the way I was doing things originally -- but there were several factors that mitigated doing that way in the future.
The mechanism I was trying to implement was a '.rc-file' capability which pre-read a number of operational values for various flags, states, file-names, directories, etc. from a custom-named file at the launch of the shell application.
For this to work in as seamless a fashion as possible, the variables defined had to look and behave identically to coded assignments in the preamble of the scripts. Leaving things in a 'token[0]', 'token[1]' array wouldn't achieve that end, particularly as token[0]/token[1] got overwritten with every successive key/value pair read from the file.
As noted earlier, in Perl this is easy -- there is even a module expressly for making this happen!
What is now in place is the following code-snippet:
do_rc () {
[ ! -r ${BASENAME}.rc ] && return -1
while read -r line
do
line=${line##\#*}
BASENAME is intended to represent the portion of $0 stripped away from path and extension elements. The routine begins by removing all comments, leading and trailing white-space, etc. It is assumed that each key/value pairing has "BASENAME" as the leading part of the the key-name (since there may be other variables defined which aren't germane to the function in question).
Assuming that a well-formed BASENAME.rc file actually exists, this will pull all the predefined values out and assign them as internal variables which can be used interchangeably with others coded directly into the routine.
Admittedly, I've omitted all the security/hardening bits which are necessary -- both because some are proprietary, and including the whole would detract from legibility.
In this thread another, simpler way has been posted. Mind that if you are going to do the indirect assigment inside a function, and want the variable to be available from global scope, read is still the way to go.
This works well if you are doing the assignment in the global scope, or just need it to be available from function scope and subscopes:
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.