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.
Related
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.
command 'which' shows the link to a command.
command 'less' open the file.
How can I 'less' the file as the output of 'which'?
I don't want to use two commands like below to do it.
=>which script
/file/to/script/fiel
=>less /file/to/script/fiel
This is a use case for command substitution:
less -- "$(which commandname)"
That said, if your shell is bash, consider using type -P instead, which (unlike the external command which) is built into the shell:
less -- "$(type -P commandname)"
Note the quotes: These are important for reliable operation. Without them, the command may not work correctly if the filename contains characters inside IFS (by default, whitespace) or can be evaluated as a glob expression.
The double dashes are likewise there for correctness: Any argument after them is treated as positional (as per POSIX Utility Syntax Guidelines), so even if a filename starting with a dash were to be returned (however unlikely this may be), it ensures that less treats that as a filename rather than as the beginning of a sequence of options or flags.
You may also wish to consider honoring the user's pager selection via the environment variable $PAGER, and using type without -P to look for aliases, shell functions and builtins:
cmdsource() {
local sourcefile
if sourcefile="$(type -P -- "$1")"; then
"${PAGER:-less}" -- "$sourcefile"
else
echo "Unable to find source for $1" >&2
echo "...checking for a shell builtin:" >&2
type -- "$1"
fi
}
This defines a function you can run:
cmdsource commandname
You should be able to just pipe it over, try this:
which script | less
I'm trying to write a Perl program which will execute a bash script. The Perl script looks like this
#!/usr/bin/perl
use diagnostics;
use warnings;
require 'userlib.pl';
use CGI qw(:standard);
ReadParse();
my $q = new CGI;
my $dir = $q->param('X');
my $s = $q->param('Y');
ui_print_header(undef, $text{'edit_title'}.$dir, "");
print $dir."<br>";
print $s."<br>";
print "Under Construction <br>";
use Cwd;
my $pwd = cwd();
my $directory = "/Logs/".$dir."/logmanager/".$s;
my $command = $pwd."/script ".$directory."/".$s.".tar";
print $command."<br>";
print $pwd."<br>";
chdir($directory);
my $pwd1 = cwd();
print $pwd1."<br>";
system($command, $directory) or die "Cannot open Dir: $!";
The script fail with the following error:
Can't exec "/usr/libexec/webmin/foobar/script
/path/filename.tar": No such file or directory at /usr/libexec/webmin/foobar/program.cgi line 23 (#3)
(W exec) A system(), exec(), or piped open call could not execute the
named program for the indicated reason. Typical reasons include: the
permissions were wrong on the file, the file wasn't found in
$ENV{PATH}, the executable in question was compiled for another
architecture, or the #! line in a script points to an interpreter that
can't be run for similar reasons. (Or maybe your system doesn't support #! at all.)
I've checked that the permissions are correct, the tar file I'm passing to my bash script exists, and also tried from the command line to run the same command I'm trying to run from the Perl script ( /usr/libexec/webmin/foobar/script /path/filename.tar ) and it works properly.
In Perl, calling system with one argument (in scalar context) and calling it with several scalar arguments (in list context) does different things.
In scalar context, calling
system($command)
will start an external shell and execute $command in it. If the string in $command has arguments, they will be passed to the call, too. So for example
$command="ls /";
system($commmand);
will evaluate to
sh -c "ls /"
where the shell is given the entire string, i.e. the command with all arguments. Also, the $command will run with all the normal environment variables set. This can be a security issue, see here and here for a few examples why.
On the other hand, if you call system with an array (in list context), Perl will not call a shell and give it the $command as argument, but rather try to execute the first element of the array directly and give it the other arguments as parameters. So
$command = "ls";
$directory = "/";
system($command, $directory);
will call ls directly, without spawning a shell in between.
Back to your question: your code says
my $command = $pwd."/script ".$directory."/".$s.".tar";
system($command, $directory) or die "Cannot open Dir: $!";
Note that $command here is something like /path/to/script /path/to/foo.tar, with the argument already being part of the string. If you call this in scalar context
system($command)
all will work fine, because
sh -c "/path/to/script /path/to/foo.tar"
will execute script with foo.tar as argument. But if you call it in list context, it will try to locate an executable named /path/to/script /path/to/foo.tar, and this will fail.
I found the problem.
changed the system command removing the second parameter and now it's working
system($command) or die "Cannot open Dir: $!";
In fairness I did not understand what was wrong on first example but now works fine, if anyone can explain probably it can be interesting understand
There are multiple ways to execute bash command/ scripts in perl.
System
backquate
exec
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
I have a shell script application.sh, as follows.
#! /bin/busybox sh
set -o nounset -o errexit
readonly emul_script="/usr/local/bin/emul.sh"
readonly profile="/etc/vendor/profile"
source "${profile}"
_usage() {
cat << EOF
${0} [-d]
-d :debug
EOF
The above script starts a specific application. My question is related to the part starting from _usage, I do not quite understand what it means and cannot see how it is used.
The << is the heredoc construct and cats everything up to the end marker (EOF in this case) to stdout.
The ${0} is the name of the input file and this will print something like the following to stdout:
application.sh [-d]
-d :debug
You are missing the trailing } by the way.
Adding to what trojanfoe says, _usage() is a shell function.
But it is never called, nor is the application itself called, so I suppse that is only part of a script.
The _usage function might be called from ${profile} script that is sourced just above it.
Beware, that you may want to put it before the source line, because, strictly speaking, it has to be defined before it is used.