I need to write a CGI program and it will display the output of a system command:
script.sh
echo "++++++"
VAR=$(expect -c " spawn ssh -o StrictHostKeyChecking=no $USER#$HOST $CMD match_max
100000 expect \"*?assword:*\" send -- \"$PASS\r\" send -- \"\r\" expect eof ")
echo $VAR
echo "++++++"
In CGI file:
my $command= "ksh ../cgi-bin/script.sh";
my #output= `$command`;
print #output;
Finally, when I run the CGI file in unix, the $VAR is a very long string including \n and some delimiters. However, when I run on web server, the output is
++++++
++++++
So $VAR is missing when passing in the web interface/browser.
I know maybe the problem is $VAR is very long string.
But anyway, is there anyway to solve this problem except writing the output to a file then retrieve it from browser?
Thanks if you are interested in my question.
script.sh uses several environment variables: $USER, $HOST, $CMD and $PASS. The CGI environment will have different environment variables set than a login shell. You may need to set these variables from your CGI script before calling script.sh.
Try finding where commands like expect and ssh that you are calling are on your system and adding their directory paths to the PATH used by your script.
I.e.
which expect
returns /usr/bin/expect then add the line:
PATH=$PATH:/usr/bin && export PATH
near the beginning of the ksh script. During debug you may also want to redirect stderr to a file by appending 2>/tmp/errors.txt to the end of your command since stderr is not shown in the browser.
my $command= "ksh ../cgi-bin/script.sh 2>/tmp/errors.txt";
Related
I have a situation where in I am calling the below Perl script
if (param("lremail") && param("lot")) {
my $address=param("lremailaddress");
my $lot=param("lot");
print a({-href=>"$dir/new.pl"},"Back to Top"),br;
print "Request submitted for $address.",br;
print "Lot $lot",br;
print "You will receive an e-mail with a link to the data when the request is complete.";
print end_html;
system ("ssh SERVERNAME /test/abc.csh $lot $$ $address &");
exit(1);
The above script does not run because when I execute the system is prompted for a password. Then I looked it up and found the below command..
expect -c 'spawn ssh SERVERNAME /test/abc.csh J213520 06 abc#gmail.com "ls -lh file"; expect "Password:"; send "PASSWORD\r"; interact'
The above command is executed successfully without any issue but from the command line only. When I incorporate the same(by replacing the system call) within the Perl script, it fails. How can I incorporate within the first script?
Reiterating and adding to comments:
Consider using a key-based authentication either with passphrase-less keys or with ssh-agent (e.g., using ssh-keygen generated/managed identities);
Consider using sshpass or another expect-like external;
Consider using the Perl Expect or an equivalent CPAN module; and/or,
Consider using the Perl Net::SSH or an equivalent CPAN module.
Also, system can easily introduce remote code execution vulnerabilities, especially when using its system LIST syntax.
I have a situation where in I am calling the below Perl script
if (param("lremail") && param("lot")) {
my $address=param("lremailaddress");
my $lot=param("lot");
print a({-href=>"$dir/new.pl"},"Back to Top"),br;
print "Request submitted for $address.",br;
print "Lot $lot",br;
print "You will receive an e-mail with a link to the data when the request is complete.";
print end_html;
system ("ssh SERVERNAME /test/abc.csh $lot $$ $address &");
exit(1);
The above script does not run because when I execute the system is prompted for a password. Then I looked it up and found the below command..
> expect -c 'spawn ssh SERVERNAME /test/abc.csh J213520 06 abc#gmail.com "ls -lh file"; expect "Password:"; send "PASSWORD\r"; interact'
The above command is executed successfully without any issue but from the command line only. When I incorporate the same(by replacing the system call) within the Perl script, it fails.
How can I incorporate within the first script?
There's an Expect module for Perl.
However, I tend to write straight expect scripts and call them from Perl. That way I can use the expect scripts on their own. But then, I used to do a lot of Tcl too.
I am working on a perl script in which I will run a command and get a output like : your id is <895162>. I will store this string and read the number from this string only . The problem is my main command will run in shell using the system command from perl .
like :
#ids.csh is "echo your id is <1123221>"
my $p = system ("./ids.csh 2>&1 > /dev/null");
print "$p\n";
$p =~ s/[^0-9]//g;
but the output is not copying to the $p file , Where I am going wrong ?
system runs a command but doesn't capture it. For that, you want qx/backticks:
my $p = `./ids.csh 2>/dev/null`;
As Len Jaffe said, you probably want to throw away stderr output (rather than displaying it to your screen or wherever your stderr is going), but not stdout (that contains the message you want to capture).
Note that when qx fails, it can do so for several different reasons and constructing a meaningful error message is not trivial. If you run into problems, consider using IPC::System::Simple's capture() instead.
You have redirected all of the output to /dev/null, which means that all of your output is being discarded.
I think you probably mean:
./ids.csh 2>/dev/null
Which will redirect stderr to /dev/null while leaving stdout unchanged.
I have a Perl script which I want to run every 4 hours through cron. But somehow it fails to execute through cron and runs fine if I run it through command line. Following is the command which I set in crontab:
perl -q /path_to_script/script.pl > /dev/null
Also, when I run this command on command prompt, it does not execute but when I go in the leaf folder in path_to_script and execute the file, it runs fine.
Also, where will the log files of this cron job be created so that I can view them?
You should probably change the working directory to "leaf folder".
Try this in your crontab command:
cd /path_to_script; perl script.pl >/dev/null
Wrt. log files. Cron will mail you the output. But since you sent stdout to /dev/null, only stderr will be mailed to you.
If you want the output saved in a log file, then pipe the stderr/stdout output of the script into a file, like so:
cd /path_to_script; perl script.pl 2>&1 >my_log_file
Usually cron will send you mail with the output of your program. When you're figuring it out, you probably want to check the environment. It won't necessarily be the same environment as your login shell (since it's not a login shell):
foreach my $key ( keys %ENV ) {
printf "$key: $$ENV{$key}\n";
}
If you're missing something you need, set it in your crontab:
SOME_VAR=some_value
HOME=/Users/Buster
If you need to start in a particular directory, you should chdir there. The starting directory from a cron job probably isn't what you think it is. Without an argument, chdir changes to your home directory. However, sometimes those environment variables might not be set in your cron session, so it's probably better to have a default value:
chdir( $ENV{HOME} || '/Users/Buster' );
At various critical points, you should give error output. This is a good thing even in non-cron programs:
open my $fh, '<', $some_file or die "Didn't find the file I was expecting: $!";
If you redirect things to /dev/null, you lose all that information that might help you solve the problem.
looks like you may have missed the
#!/usr/bin/perl
at the start of your perl script which is why you might need perl -q to run it
once you have added that line you can run it directly from the command line using
/path_to_script/script.pl
If you use a command in your perl program, i advise you to put the full path to the command in your program.
I have try to load environment but it is not more helpful.
After a oversee with one colleague, i think it's from interaction between perl and the system environment.
Best regards,
Moustapha Kourouma
I am trying to send a get or a post through a command-line argument. That is test the script in the command line before I test through a browser (the server has issues). I tried searching online, and I suppose I was probably using incorrect terminology because I got nothing. I know this is possible because I saw someone do it. I just don't remember how it was done.
Thanks! :)
To test a CGI program from the command line, you fake the environment that the server creates for the program. CGI.pm has a special offline mode, but often I find it easier not to use because of the extra setup I need to do for everything else my programs typically expect.
Depending on the implementation of your script, this involves setting many environment variables, which you can do from a wrapper script that pretends to be the server:
#!/bin/bash
export HTTP_COOKIE=...
export HTTP_HOST=test.example.com
export HTTP_REFERER=...
export HTTP_USER_AGENT=...
export PATH_INFO=
export QUERY_STRING=$(cat query_string);
export REQUEST_METHOD=GET
perl program.cgi
If you're doing this for a POST request, the environment is slightly different and you need to supply the POST data on standard input:
#!/bin/bash
export CONTENT_LENGTH=$(perl -e "print -s q/post_data/");
export HTTP_COOKIE=...
export HTTP_HOST=test.example.com
export HTTP_REFERER=...
export HTTP_USER_AGENT=...
export PATH_INFO=...
export QUERY_STRING=$(cat query_string);
export REQUEST_METHOD=POST
perl program.cgi < post_data
You can make this as fancy as you need and each time you want to test the program, you change up the data in the query_string or post_data files. If you don't want to do this in a shell script, it's just as easy to make a wrapper Perl script.
Are you using the standard CGI module?
For example, with the following program (notice -debug in the arguments to use CGI)
#! /usr/bin/perl
use warnings;
use strict;
use CGI qw/ :standard -debug /;
print "Content-type: text/plain\n\n",
map { $_ . " => " . param($_) . "\n" }
param;
you feed it parameters on the command line:
$ ./prog.cgi foo=bar baz=quux
Content-type: text/plain
foo => bar
baz => quux
You can also do so via the standard input:
$ ./prog.cgi
(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)
foo=bar
baz=quux
^D
Content-type: text/plain
foo => bar
baz => quux
Old discussion, but I was looking for the same answers - so for those who follow - this is what I found out
RTFM! from the CGI man page ( and there is more )
DEBUGGING
If you are running the script from the command line or in the perl
debugger, you can pass the script a list of keywords or parameter=value
pairs on the command line or from standard input (you don't have to
worry about tricking your script into reading from environment
variables). You can pass keywords like this:
your_script.pl keyword1 keyword2 keyword3
or this:
your_script.pl keyword1+keyword2+keyword3
or this:
your_script.pl name1=value1 name2=value2
or this:
your_script.pl name1=value1&name2=value2
To turn off this feature, use the -no_debug pragma.
If you don't want to alter the perl script, you can call it with at least two environment variables set, as others mentioned already. To simulate a GET request:
shell$ QUERY_STRING=limit=20 REQUEST_METHOD=GET ./events_html.pl
That's the console shortcut for www.myserver.org/events_html.pl?limit=20
Yes, it's possible to do this from the command line, bypassing your server. This page explains all: Perl CGI debugging (sitewizard.com) (Especially item 6 on that page). Here I quote the most important part:
To test the script offline using the
GET method, simply set the
QUERY_STRING environment variable
accordingly. If you are using Windows,
you might use the following command
line in a DOS window prior to running
the script in the same window:
set QUERY_STRING=recipient=John#Doe.com&Fullname=M+Name
To test the script offline using the
POST method, put the line below into a
text file named, say, testinput.txt.
recipient=John#Doe.com&Fullname=M+Name
Then redirect that file as an input to
the script. On Unix systems as well as
under Windows' MSDOS prompt, you can
do it this way:
perl -w scriptname.pl < testinput.txt
Your script will then receive that
input as though it was sent it by a
form on the website. Check the error
messages that perl spouts, if any, to
help you track the problem in the
script.
To give a cgi script post data:
$ echo -n 'a=b;c=d' | REQUEST_METHOD=POST CONTENT_LENGTH=999 perl index.cgi
To give a cgi script get data:
$ perl index.cgi 'a=b;c=d'
LWP comes with ready made scripts that can be used from the command-line. Check for GET and POST scripts in your system.
In Windows, you can use VBScript to write a command line util that calls into the MS XML library:
Dim XMLHttp : Set XMLHttp = CreateObject("Microsoft.XMLHTTP")
On Error Resume Next
strIPAddress = WScript.Arguments(0)
strMACAddress = WScript.Arguments(1)
strSubnetMask = WScript.Arguments(2)
On Error Goto 0
WScript.Echo "Attempting to wake host " & strIPAddress & " on NIC " & strMACAddress &
"using netmask " & strSubnetMask
strGetUrl = http://wolService/WolService/WolService.asmx/WakeBroadcast?hostIP=" &
strIPAddress & "&macAddress=" & strMACAddress & "&subnetMask=" & strSubnetMask
XMLHttp.Open "GET", strGetUrl, False
XMLHttp.Send ""
WScript.Echo XMLHttp.ResponseText
Edit: This script sends HTTP requests and can be used from the command line. I got confused by the question 'How can I send POST and GET data to a Perl CGI script via the command line' and thought this was about sending POST and GET data to a Perl CGI script via the command line from an unspecified client OS.