can someone tell what this code snippet does - linux

I am trying to understand this below mentioned code snippet, currently i am stuck at line number 3 and after digging alot i got to know that $MYPERL is where perl binaries are defined/located and for $PERLDB is what perl debugger i,e -d:ptkdb and basically this is a perl script and some how person who coded this wrapps it to use the latest perl version. can some one tell me how i can change MYPERL variable value /home/Desktop/goudar/perl/ and execute rest of the script ?
#!/bin/sh
# -*- cperl -*-
exec $MYPERL -x $PERLDB -wS $0 ${1+"$#"}
#!perl
#line 6
### perl
use Cwd;
use Data::Dumper;
use List::MoreUtils qw/ uniq /;
use JSON;
use Mojo::JSON;
#rest of the code go here#

can someone tell what this code snippet does
It executes the embedded Perl script using the Perl interpreter specified by env var MYPERL. Options specified in env var PERLDB (if any) are passed to the interpreter. Warnings are enabled globally.
how i can change MYPERL variable value /home/Desktop/goudar/perl/ and execute rest of the script
If the process that will launch the script is a bourne-based, then
export MYPERL=/home/Desktop/goudar/perl/
That said, I don't know why you want to assign that value to the MYPERL env variable since the script expects it to be the path to a Perl interpreter.

Related

how to get a variable of a python file from bash script

I have a python file, conf.py which is used to store configuration variables. conf.py is given below:
import os
step_number=100
I have a bash script runner.sh which tries to reach the variables from conf.py:
#! /bin/bash
#get step_number from conf file
step_number_=$(python ./conf.py step_number)
However, if I try to print the step_number_ with echo $step_number_, it returns empty value. Can you please help me to fix it?
$(command) is replaced with the standard output of the command. So the Python script needs to print the variable so you can substitute it this way.
import os
step_number = 100
print(step_number)

Perl set and get env in different bash script

I have created a perl script which invokes two bash script. First script will set a envirnomental variable and the second will echo the environmental variable. I have given the contents of the files bellow
# perlscript.pl
print `. setnameenv.sh`;
print `. getnameenv.sh`;
# setnameenv.sh
export my_msg='hello world!'
# getnameenv.sh
echo $my_msg
now when I run the perl script perl perlscript.pl I am expecting the 'hello world' to be printed on the screen but actually I don't see any output. I there any way to do this without modifying the bash scripts?
You can embed perl into bash script,
#!/bin/bash
. setnameenv.sh
exec perl -x "$0" "$#"
#!perl
# your script below
print `. getnameenv.sh`;
From perldoc
-x
-xdirectory
tells Perl that the program is embedded in a larger chunk of unrelated text, such as in a mail message. Leading garbage will be discarded until the first line that starts with #! and contains the string "perl". Any meaningful switches on that line will be applied.
You spawn a shell, execute some commands to change its environment, then exit the shell. You never used the environment variable you created before exiting the shell. If you want a perl to see it, you're going to have to launch Perl from that shell.
. setnameenv.sh ; perlscript.pl
If you can't change how perlscript.pl is launched, you have a couple of options, none of which are that friendly. One of the options is to bootstrap.
BEGIN {
if (!length($ENV{my_msg})) {
require String::ShellQuote;
my $cmd = join(' ; ',
'. setnameenv.sh',
String::ShellQuote::shell_quote($^X, $0, #ARGV),
);
exec($cmd)
or die $!;
}
}
This can now be done in Perl with the Env::Modify module.
use Env::Modify qw(source);
source("setnameenv.sh");
# env settings from setnameenv.sh are now available to Perl
# and to the following system call
print `. getenvname.sh`; # or source again, like source("getenvname.sh")
The child process can inherit the parent's environment but cannot make any changes. Similarly the parent cannot have access to the child's environment as well. Hence to catch environment of the child in parent the child should print the values as shown in the bellow code. The below code will set already existing environment variables as well, but this can be optimized
# perlscript.pl
my $env_val = `. setnameenv.sh; env`;
my #env_list = split "\n", $env_str;
foreach (#env_list)
{
/([\w_]+)=(.*)/;
$ENV{$1} = $2;
}
print `. getnameenv.sh`;
find the actual explanation in this SO answer
Variables are only exported for the child processes.
You cannot export variables back to the father process.
You'll need another way to transport variables back to the father or the brothers.
For example, here is a example where all exported variables are saved and read from a file :
#!/bin/dash
# setnameenv.sh
export my_msg='hello world!'
export > savedVariables.sh
and
#!/bin/dash
# getnameenv.sh
. ./savedVariables.sh
echo "$my_msg"
Note : this works with dash. bash generates one line he cannot read back.

Backslashes in command-line argument under Cygwin

I am passing in the full path to a file as a commandline argument in perl.
For example
myscript.pl C:\Dir\myfile.txt
In myscript.pl, I have
my $full_path = shift;
print $full_path;
When I do this, my output is
C:Dirmyfile.txt
What I really want is C:\Dir\myfile.txt
But when I run my script as
myscript.pl 'C:\Dir\myfile.txt'
my output is C:/Dir/myfile.txt. Now it has forward slashes instead of backslashes. How do I get what I want? (The same text as what was passed in, file path with backslashes)
I need to run be able to run this script on Cygwin in a windows environment. Note that the script serves a larger purpose, but what I have posted is the part I am stuck with. The path is something I copy from somewhere else, so I really don't want to do the extra work of replacing backslash with forward slash or spaces.
use the File::Spec module. This simplifies passing parameters to your script, since you don't need to use slashes, and it also makes your application portable across operating systems.
use File::Spec;
my $full_path = File::Spec->catfile(#ARGV);
print $full_path, "\n";
Example:
perl myscript.pl C: Dir myfile.txt
C:\Dir\myfile.txt
Alternatively, if you need to use the full path string, then use the following line in place of the above:
my $full_path = File::Spec->canonpath($ARGV[0]);
Example 2:
perl myscript.pl C:\Dir\myfile.txt
--OR--
perl myscript.pl C:/Dir/myfile.txt
C:\Dir\myfile.txt
Example 3 (for Cygwin) - surround parameter with single quotes:
perl myscript.pl 'C:\Dir\myfile.txt'
C:\Dir\myfile.txt

Can I find out who called a zsh script?

Assume a script master.sh, which is called as
./foo/bar/master.sh
and contains the lines
#!/bin/zsh
. ./x/y/slave.sh
Is it possible to find out from within slave.sh, that the script which is doing the sourcing, is ./foo/bar/master.sh ?
I can not use $0 here, because this would return ./x/y/slave.sh.
I'm using zsh 5.0.6
one way you can achieve this is that for the child script to take as optional argument the name of the caller. Thus this would be accessible with `$1``
ex:
#!/bin/zsh
# master/leader
. ./x/y/slave.sh $0 # or hardcoded path
#!/bin/zsh
# slave/worker
echo "Here is my master $1"
(you can also do another custom protocol using a environment variable set by the master)
(this solution would also works on bash, and other shell)
The information can already be obtained in zsh right now (thanks to Bart Schaefer, who pointed out to me the existence of the variable functrace in the zsh/parameter module):
#!/bin/zsh
# slave/worker
zmodload zsh/parameter
echo "Here is my master ${functrace[$#functrace]%:*}"
The '%:*' is necessary, because the entries in the functrace array also contain the line number of the call.

difference between ./test.pl and perl test.pl

Code
#!/usr/bin/perl -I/root/Lib/
use Data::Dumper;
print Dumper \#INC;
The above code file name is test.pl and the permission is 755.
When I am running the program using /usr/bin/perl test.pl the output of the #INC contains "/root/Lib" at the end. It is like push in to #INC.
/usr/bin/perl test.pl Output
$VAR1 = [
'/etc/perl',
'/usr/local/lib/perl/5.10.0',
'/usr/local/share/perl/5.10.0',
'/usr/lib/perl5',
'/usr/share/perl5',
'/usr/lib/perl/5.10',
'/usr/share/perl/5.10',
'/usr/local/lib/site_perl',
'.',
'/root/Lib/'
];
But when I am running the program using ./test.pl the output of the #INC contain "/root/Lib/" contain first as well as end also. It is like unshift and push.
./test.pl output
$VAR1 = [
'/root/Lib/',
'/etc/perl',
'/usr/local/lib/perl/5.10.0',
'/usr/local/share/perl/5.10.0',
'/usr/lib/perl5',
'/usr/share/perl5',
'/usr/lib/perl/5.10',
'/usr/share/perl/5.10',
'/usr/local/lib/site_perl',
'.',
'/root/Lib/'
];
So I want to know what is the difference between ./test.pl and /usr/bin/perl test.pl ?
There are two questions lurking here. The headline question is "What's the difference between ./test.pl and perl test.pl?", while the secondary question is "Why is /root/Lib added at the front of #INC when the script is run as ./test.pl and not when run as perl test.pl?"
An answer, not necessarily applicable to your situation, is that ./test.pl runs the Perl interpreter specified by the shebang (/usr/bin/perl), whereas perl test.pl runs whatever Perl interpreter is found first on your $PATH (or aliases or functions). These need not be the same version of Perl. For me, they very seldom are the same version of Perl; the one in /usr/bin is usually relatively old and the one on my $PATH is relatively new (5.8.x vs 5.18.x, for example).
Working with Perl 5.12.4 (ouch; that's old) from /usr/bin on my machine, and using your script, I see:
$ perl test.pl
$VAR1 = [
'/root/Lib/',
'/Library/Perl/5.12/darwin-thread-multi-2level',
'/Library/Perl/5.12',
'/Network/Library/Perl/5.12/darwin-thread-multi-2level',
'/Network/Library/Perl/5.12',
'/Library/Perl/Updates/5.12.4',
'/System/Library/Perl/5.12/darwin-thread-multi-2level',
'/System/Library/Perl/5.12',
'/System/Library/Perl/Extras/5.12/darwin-thread-multi-2level',
'/System/Library/Perl/Extras/5.12',
'.'
];
$ ./test.pl
$VAR1 = [
'/root/Lib/',
'/root/Lib/',
'/Library/Perl/5.12/darwin-thread-multi-2level',
'/Library/Perl/5.12',
'/Network/Library/Perl/5.12/darwin-thread-multi-2level',
'/Network/Library/Perl/5.12',
'/Library/Perl/Updates/5.12.4',
'/System/Library/Perl/5.12/darwin-thread-multi-2level',
'/System/Library/Perl/5.12',
'/System/Library/Perl/Extras/5.12/darwin-thread-multi-2level',
'/System/Library/Perl/Extras/5.12',
'.'
];
$
Note that here the /root/Lib name is added once or twice to #INC. My best guess is that when you use perl test.pl, Perl scans the shebang and adds the -I option if finds there. When you use ./test.pl, the kernel runs /usr/bin/perl -I/root/Lib test.pl (where we can negotiation on whether the name test.pl appears on the command line; the key point is that the -I/root/Lib does appear), so Perl adds /root/Lib once because of the explicit -I provided by the kernel, and then adds another because it parses the shebang line.
See: perldoc perlrun for many more details.
You should use lib instead. That way, execution is consistent.
#!/usr/bin/perl
use lib qw( /root/Lib/ );
use Data::Dumper;
print Dumper \#INC;
See http://perldoc.perl.org/lib.html
When you run it as perl test.pl, among the first things it does is look to see if there is a line starting with #!. If it finds one it tries to act as if it were called with those arguments.
So the following adds warnings
#! perl -w
If you run it as ./test.pl your system actually runs it with those arguments. Perl really doesn't have a way of knowing that it was called implicitly like that. So Perl just parses that line itself like it did previously.
In your case that means that /root/Lib/ will be added to #INC twice.
The reason it appears at the beginning of the list; is that when Perl is actually called with that option, it adds it before it has a chance to load '#INC with anything.
If it gets added when parsing #!, it has already populated #INC so it adds it at the end.

Resources