bdimych has asked for the wisdom of the Perl Monks concerning the following question:
Hello monks!
My problem - to make global %ENV uppercase only. Script must launch other programs which require uppercase environment
I think about:
1) tie %ENV, 'my_uppercase_env';
I already tried this, but %ENV became tied only "partially" and its behaviour was unpredictable. But if do carefully, I think nevertheless its possible in this way.
2) just simple access methods Eget, Eset, Edel, Eexs
3) Define some intermediate %ENV_, tie it, and in its methods do with real %ENV
What is the best way ? Or may be another way?
Thanks.
Re: Case insensitive keys in global %ENV
by CountZero (Bishop) on Aug 15, 2007 at 08:46 UTC
|
Are you really sure it is a good idea to mess around %ENV and make it all uppercase on such a wholesale basis? There may be other programs or routines which expect the %ENV not to be changed like that.It seems very strange to me that these other programs (can you give an example?) require uppercase %ENV only. Do these programs require the keys or the values or both of %ENV to be in uppercase?
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] |
Re: Case insensitive keys in global %ENV
by derby (Abbot) on Aug 15, 2007 at 12:33 UTC
|
*nix right? If so, then changing %ENV only affects the running program and any children. If that's what you need to do, then that's what you need to do. The only real question is do you need the lowercase (or mixed case) entry to still be around. If not, then something like this works fine:
foreach my $key ( keys %ENV ) {
my $val = $ENV{$key};
delete $ENV{$key};
$ENV{ uc $key } = $val;
}
if you don't mind the *dupes* (not really) entries, then you can simplify even further:
foreach my $key ( keys %ENV ) {
$ENV{ uc $key } = $ENV{$key};
}
So what's really the problem -- I see no need for something extreme.
| [reply] [d/l] [select] |
|
use my_future_runtime;
my $x = get_command_line_param(); # $x may be mixed case
my $y = read_some_file(); # $y may be mixed case
sub_which_add_new_key($x, 'value_for_cobol');
sub_which_delete_key($y);
launch_cobol_prog();
imho, tie the "most right" way in such situation. | [reply] [d/l] |
Re: Case insensitive keys in global %ENV
by jbert (Priest) on Aug 15, 2007 at 09:38 UTC
|
As others have said, this is a very unusual requirement, so are you sure of it?
If you're on Unix, the easiest/safest way might be to:
- Fork (so you can mess with your child process's copy of the environment without affecting your own copy)
- Loop over each key - delete the key from %ENV, uppercase both key and val, stash them back into %ENV
- exec your child program (your modified environment should be preserved).
You could avoid the fork by keeping a copy of your original environment and then putting it back, but this would be a bit dangerous, since you're messing with process-wide variables here, which could in principle be accessed from a signal handler even if you aren't multi-threaded. | [reply] |
Re: Case insensitive keys in global %ENV
by Anno (Deacon) on Aug 15, 2007 at 10:08 UTC
|
Choosing from the alternatives
1) tie %ENV, 'my_uppercase_env';
2) just simple access methods Eget, Eset, Edel, Eexs
3) Define some intermediate %ENV_, tie it, and in its methods do with real %ENV
is a trade-off between the effort to implement the solution and the effort to adapt the (existing?) code that expects case-insensitive access to %ENV.
1) is the hardest one to implement, as you have noted. %ENV is magical, and tie-ing a magical variable is bound to be tricky. On the other hand, it requires no change at all to the code that uses it. You'd need that method if you can't change that code at all. If you can, choose one of the others.
2) is the simplest one to implement, but it would presumably require hand-editing the code that uses it, replacing every access to %ENV with the appropriate access method.
3) is in effect a wrapper around 2). It needs extra effort to embed the access methods in a tied hash. The advantage would be that you could mechanically change the using code, applying something like s/([%@$])ENV/${1}ENV_/g.
In this view, the choice would depend on how hard it is to adapt the code that needs a caseless %ENV.
Anno | [reply] [d/l] [select] |
Re: Case insensitive keys in global %ENV
by cdarke (Prior) on Aug 15, 2007 at 09:49 UTC
|
Your inconsistency might be because of the tie method not updating the 'real' %ENV. Consider using Env::C (or at least read its doc to see the issues). I agree with others though: why would you want to do this? | [reply] |
Re: Case insensitive keys in global %ENV
by bruceb3 (Pilgrim) on Aug 15, 2007 at 09:12 UTC
|
Maybe you could just have a wrapper around the calling of the other programs that forks, to make a copy of the environment, and then uppercases the environment and then starts the other programs.
This way you don't have to worry about keeping the environment in upper case at all times. | [reply] |
Re: Case insensitive keys in global %ENV
by bdimych (Monk) on Aug 15, 2007 at 11:36 UTC
|
Many thanks.
This problem is strange, but it's my formal task. I am not main project designer. I have limited "free-hand". Project's aim is to make some runtime library with own internal data and additional ENV manipulation functionality. I know that some future functions in this library will launch some cobol programs that require uppercase ENV, that's all. Now I'm at the beginning and want to deside how to make this better for the future tasks.
I thought about this like Anno wrote. Thanks him for advise not tie magical vars, I didnt knew it. I may change code. So only two or even "one and a half" ways remain. | [reply] |
Re: Case insensitive keys in global %ENV
by apl (Monsignor) on Aug 15, 2007 at 10:57 UTC
|
Consider having your second process (which requires %ENV variables to be upper-case) to explicitly use uc on all such references.
For example, my $svr = uc( $ENV{DBSERVER} );
This enforces the upper-case requirement on the only process that requires it, and doesn't impact anything else.
Please ignore. It's the subscript to %ENV that needs to be upper-case, not the value of %ENV that needs to be upper-case.
| [reply] [d/l] |
Re: Case insensitive keys in global %ENV
by Anonymous Monk on Aug 15, 2007 at 08:52 UTC
|
%ENV is already uppercase only,
C:\>perl -le"$ENV{lowerlowerlower}=1;print for keys %ENV"
USERPROFILE
HOMEDRIVE
CLIENTNAME
COMMONPROGRAMFILES
APPDATA
PROGRAMFILES
OS
PATHEXT
PROMPT
NUMBER_OF_PROCESSORS
HOMEPATH
PATH
USERDOMAIN
PROCESSOR_ARCHITECTURE
TEMP
SYSTEMDRIVE
COMSPEC
WINDIR
PROCESSOR_LEVEL
USERNAME
LOWERLOWERLOWER
PROCESSOR_IDENTIFIER
ALLUSERSPROFILE
COMPUTERNAME
C:\>
Don't count on a specific environment variable existing in %ENV. Don't
count on %ENV entries being case-sensitive, or even case-preserving.
Don't try to clear %ENV by saying "%ENV = ();", or, if you really have
to, make it conditional on "$^O ne 'VMS'" since in VMS the %ENV table is
much more than a per-process key-value string table.
| [reply] [d/l] |
|
Maybe on windows but not a UNIX.
bruce:0:~/tmp $ export fred=1
bruce:0:~/tmp $ env | grep fred
fred=1
bruce:0:~/tmp $ perl -e 'print $ENV{fred},"\n"'
1
bruce:0:~/tmp $ perl -e 'print $ENV{FRED},"\n"'
bruce:0:~/tmp $
| [reply] [d/l] |
|
|