$ENV{$variable} in perl - perl

Is that anyway in Perl to expand the variable by in $ENV{$variable}?
I exported "a=T" and "T=b" in shell, and I run the Perl script in which print "$ENV{$a}\n", but nothing printed. I want to "b" can be printed, then how should I do in Perl?

Those environment variables should be chained you say, so
$ENV{ $ENV{a} };
Note: not $a but a, like $ENV{USER} etc. This uses the hash %ENV (see perlvar), which has the current environment, so with keys being names of environment variables.
It is apparently of interest to use a Perl variable (for the shell variable's name†) in %ENV, and not a string literal as above. In that case we need to pass that shell variable, its name or the value, to the Perl program somehow so to have it stored in a variable; can't just use it directly.
Incidentally, one of the ways to pass a variable from shell to Perl is precisely by exporting it, what then makes it available via %ENV. However, it can also be passed as usual, via command line. Assuming the use of a Perl one-liner (common in shell scripts), we have two options for how to pass
As an argument, perl -we'...' "$var", in which case it is available in #ARGV
Via the -s command switch, perl -s -we'...' -- -shv="$var", what sets up $shv variable in the one-liner, with the value $var. The -- mark the start of arguments.
See this post for details, and perhaps this one for another, more involved, example.
Note A comment asks how to pass variable's name (string a), not its value ($a). This doesn't seem as the best design to me; if the name of a variable for some reason need be passed around then it makes sense to store that in a variable (var="a") and pass that variable, as above.
But if the idea is indeed to pass the name itself around, then do that instead, so either of
perl -we'...' "a"
perl -we'...' -s -- -shv="a"
The rest is the same and %ENV uses the variable that got assigned the input.
If a full Perl script is used (not a one-liner) then use Getopt::Long to nicely handle arugments.
† A comment asks about passing the shell variable's name to a Perl variable — so a from the OP, not its value $a. I am a little uncertain of the utility of that but it is of course possible.
The two ways for how to pass a variable from shell to Perl then differ in what is passed.

Related

Capturing output from a command specified in Perl array

I thought this must be simple, but I haven't found a viable solution.
The problem is as simple as this: I want to execute a system command and capture the output in Perl variable. The command is specified in Perl array (containing command and parameters, e.g. #cmd = ('mycmd', '-opt1', 'arg1', 'val1')).
I don't want to use forking, i.e. open(FROM_KID, '-|') is not an option. I know that if I had the command in a string I can achieve this with backticks. So perhaps this problem reduces to converting #cmd array into a string. In my case, the command arguments can contain spaces.
Is there a simple way to convert #cmd array into string that can be used with backticks, but such that all arguments are properly quoted? Also ideally without using any external libraries.
Thanks!!
You may be looking for String::ShellQuote. Note that only Bourne shell quoting is supported.
But backticks also perform an implicit fork, and if they in any way differ from the implicit fork of pipe open, I for one never noticed. :-\

call the subroutine of the shell script from perl script and pass certain parameters to it

How can i call the subroutine of the shell script and pass certain parameters to it? something like below ?
#!/usr/bin/perl
### need something like this
source file.sh
routine; # <-- this is supposed to be part of file.sh which is called
# from perl script and some parameter are passed to it
No. They are two different languages. All you can do is call a shell script from Perl as a child process, using, for example, system() or qx().
Write your program in one language, Perl or shell, don't try to mix them.
OK, it is possible to export a function from a shell and then parse and execute it in Perl, but it is a lot of work, insecure, and usually not worth the effort.
A hack around this problem would be to isolate the content of routine out of file.sh into subfile.sh - then you can do this in Perl:
#cmdargs=('subfile.sh', $arg1, "arg2");
system(#cmdargs);
The first list element is the command, the second the value of a Perl variable being passed as an argument to subfile.sh; the third is a literal being passed as an argument to subfile.sh.
Avoid maintenance issues between the copy of routine's contents in subfile.sh and file.sh by writing a wrapper for subfile.sh in file.sh and simply call it with the appropriate arguments, like any other shell command, wherever you're calling routine in file.sh.
I think that would work.

Pass variable from perl script to shell script in Unix

Am pretty much aware of passing variables between shell scripts using 'EXPORT' command. But am stuck with passing a variable value from a perl script to shell script in UNIX operating systems.
Let me explain it clearly.
I have a parent shell called parent_shell.sh. Inside this shell script am using a variable called 'file_name' which I should fetch from child perl script.
So inside my parent_shell.sh script it will be like as follows,
perl my_perl_script.pl
file_name = 'variable' #from perl above perl script
Hope this is clear. Please let me know if it is not clear.
Thanks
Modifying the global %ENV hash in perl is equivalent to exporting variables in shell.
However, exporting variables in environment, in any language, only affects child processes, period. You can't modify parent process environment in any way.
The child script can only return anything by printing on standard output and standard error and by it's status, but that is a number 0-127 (well, it's a number 0-255, but shell can only reliably process the values up to 127).
If you just need one value from the perl script, simply print the value and use process substitution from the shell:
file_name=$(perl my_perl_script.pl)
if it is more, you can print a shell code to set the variables and use shell's eval, but make sure you quote the values correctly before printing from perl.

$> and $? in Perl

In Perl, do $> and $? have special meaning in the same way that $_ and #_ are "special"?
Yes, there are many special variables whose name is a single punctuation character, including the scalar variable > (written $>) and the scalar variable ? (written $?). They are documented in perldoc perlvar.
$> is the process's effective user ID. It's “magical” in that assigning to it will change the EUID (if permitted).
$? contains the status of the last external process call. It's a little magical (e.g. you can only assign integers to it), but mainly several built-in constructs (such as backticks, i.e. `foo`) assign to it.

How can I use the value of a variable as a variable name in Perl?

If I have a variable, $bar, which is equal to string "foo" and $foo is equal to 0xdead, how can I get $foo's value while I only have the the string for the variable name?
Essentially, I want to do a kind of pointer indirection on the global namespace or a hash lookup on the global namespace.
The following didn't work:
perl -e 'my $foo=0xdead; my $bar ="foo"; print ${$bar}."\n";'
It only prints the newline.
This trick works only with global variables (symbolic references seek the symbol table of the current package), i. e.
perl -e '$foo=0xdead; my $bar ="foo"; print ${$bar}."\n";'
If you want to catch lexicals, you'll have to use eval ""
perl -e 'my $foo=0xdead; my $bar ="foo"; print eval("\$$bar"),"\n";'
But using eval "" without purpose is considered bad style in Perl, as well as using global variables. Consider using real references (if you can).
There are very very very preciously few instances in Perl where you must use symbolic references. Avoiding symbolic references in all other instances is not about style. It is about being a smart programmer. As mjd explains in Why it's stupid to "use a variable as a variable name":
The real root of the problem code is: It's fragile. You're mingling unlike things when you do this. And if two of those unlike things happen to have the same name, they'll collide and you'll get the wrong answer. So you end up having a whole long list of names which you have to be careful not to reuse, and if you screw up, you get a very bizarre error. This is precisely the problem that namespaces were invented to solve, and that's just what a hash is: A portable namespace.
See also Part 2 and Part 3.
Without my and with $$bar works for me:
$ perl -e '$foo=0xdead;$bar ="foo"; print $$bar."\n";'
57005
You can find out more about using a variable as a variable name in the Perl FAQ List.