Open file in perl with sudo - perl

I'd like to write data to a file, but the file handle should be opened with sudo or else I get permission denied error. But looks like something like following is not possible in perl?
sudo open (FH, "> $filename") or die "$!\n";

sudo is a linux command, it is not a Perl function. You can run the whole Perl script with sudo (sudo perl script.pl), or you can change your user id in Perl by assigning to $< and $> special variables (see perlvar - Perl predefined variables) which will only be possible with extra privileges, anyway.
BTW, open sets $! on failure, not $#.

open(my $pipe_fh, '-|', 'sudo', 'cat', $filename) or die "Unable to open pipe: $!\n";
It creates another process to solve your problem that may be better solved by running the script with the correct rights.

Related

How to remove carriage return in Perl properly?

I have a code that looks like this
sub ConvertDosToUnix{
my $file = shift;
open my $dosFile, '>', $file or die "\nERROR: Cannot open $file";
select $dosFile;
print("Converting Dos To Unix");
`perl -p -i -e "s/\r//g" $dosFile`;
close $dosFile;
}
Also, the perl command works when I used that outside the subroutine or in the main function. But when I created a separate subroutine for converting dos to unix, I got an error that says:
sh: -c: line 0: syntax error near unexpected token `('
//g" GLOB(0x148b990)' -p -i -e "s/
In which I don't understand.
Also, I also tried dos2unix but for some reason, it doesn't totally remove all the carriage returns like the perl command.
Honestly, you seem a little confused.
The code you have inside backticks is a command that is run by the shell. It needs to be passed a filename. You have your filename in the variable $file, but you pass it the variable $dosFile which contains a file handle (which stringifies to "GLOB(0x148b990)" - hence your error message).
So all your work opening the file is wasted. Really, all you wanted was:
`perl -p -i -e "s/\r//g" $file`
But your system almost certainly has dos2unix installed.
`dos2unix $file`
I should also point out that using backticks is only necessary if you want to capture the output from the command. If, as in this case, you don't need the output, then you should use system() instead.
system('dos2unix', $file);

Is there a way to execute a file and one line of program in perl?

I want to execute some code before execution(redirect stderr to stdout).
perl -e "BEGIN {open STDERR, '>&STDOUT'}" perl.pl
But when there is -e, no file will be executed. I know $Config{sitelib}/sitecustomize.pl can pre-execute some code, and -f option can disable it. But this way is inflexible. In most cases, I do not need to add extra code. I don't want to add -f every time.
I cannot use shell to redirect. I want to set org-babel-perl-command in emacs org mode so that stdout and stderr can be printed in the same way, instead of opening another window to print stderr. org-babel-perl-command should be like perl.
For example, org-babel-python-command can be set to python -i -c "import sys; sys.stderr = sys.stdout".
perl -e'
open( STDERR, ">&STDOUT" );
do( shift( #ARGV ) );
' perl.pl
(Error handling needed.)
For the case in question, the following would suffice:
perl perl.pl 2>&1
Maybe even
./perl.pl 2>&1
You could just make a wrapper for perl. For example:
#!/bin/bash
exec perl "$#" 2>&1
Then make it executable and use instead of perl in your org-babel-perl-command. Ensure it can be found in your PATH or use full location.

Perl runtime bug in OGS HPC cluster

I'm attempting to debug a HPC cluster.
One problem: submitting Perl scripts into a several hundred node Linux Suse cluster via Open Grid Scheduler (OGS/GE 2011.11).
This generates a runtime error for Perl scripts on the "long queue" in the cluster, but not on the "short queue".
$> qsub -cwd -q short.q ./test.pl
Output is ok
$> qsub -cwd -q long.q ./test.pl
Output error log,
/var/spool/sge/comp26/job_scripts/3141815: line 2: syntax error near unexpected token my'
/var/spool/sge/comp26/job_scripts/3141815: line 2:open (my $fh, '>', 'test.out');'
If I submit a shell script to the long queue it works, containing
perl ./test.pl
Any ideas?
System: GNU bash, version 4.2.46(2), Perl v5.16.3 (yuk)
Test script
#!/usr/bin/perl
# Also tried #!/bin/perl
system("perl -v > perl.out");
open (my $fh, '>', 'test.out');
print $fh 'test';
close $fh;
The solution,as #bytepusher described, was
#!/usr/bin/env perl
and submission to qsub -cwd -q long.q ./test.pl was fine.

Can we create bash instance in perl script?

I am trying to use Perl to create a process running bash and then create a file sample.txt, but after the bash command I can't see any output on the console or any sample.txt file in the same directory structure. Can somebody help me to fix following code?
my $var = `bash -l`;
system($var);
print "Done!";
my $filename = 'sample.txt';
open(my $fh, '>', $filename) or die "Could not open file '$filename' $!";
chmod(0777, "sample.txt");
print $fh "hello";
close $fh;
print "Done 1!..";
Bash's -l argument is convincing it to stay interactive. Running:
perl -e 'print `bash -l`'
On its own has the bash process bound to stdin interactively, but the subprocess's output is captured by perl and printed later when bash exits, which it will only do when you press ControlD, issue exit or logout etc.
You probably wanted to start with $var = 'bash -l';. That will start bash interactively at first, and when you exit, will continue the remainder of the program. To me it's unusual to want to do this and I expect you should write something for bash that exits normally, probably with the -c argument.
Replacing your first two lines of code with:
system("bash", "-c", "echo Hello World!");
accomplishes this and the remainder of the program executes normally. I'm unsure what you wanted bash to do for you however. These example cases would be better accomplished with just
system("echo", "Hello World!") or print "Hello World!".

Perl - One liner file edit: "perl -n -i.bak -e "print unless /^$id$,/" $filetoopena;" Not working

I cannot get this to work.
#!/usr/bin/perl -w
use strict;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
my $id='123456';
my $filetoopen = '/home/user/public/somefile.txt';
file contains:
123456
234564
364899
437373
So...
A bunch of other subs and code
if(-s $filetoopen){
perl -n -i.bak -e "print unless /^$id$,/" $filetoopen;
}
I need to remove the line that matches $id from file $filetoopen
But, I don't want script to "crash" if $id is not in $filetoopen either.
This is in a .pl scripts sub, not being run from command line.
I think I am close but, after reading for hours here, I had to resort to posting the question.
Will this even work in a script?
I tried TIE with success but, I need to know alternatively how to do this without TIE::FILE.
When I tried I got the error:
syntax error at mylearningcurve.pl line 456, near "bak -e "
Thanks for teaching this old dog...
First of all (this is not the cause of your problem) $, (aka $OUTPUT_FIELD_SEPARATOR) defaults to undef, I'm not sure why you are using it in the regex. I have a feeling the comma was a typo.
It's unclear if you are calling this from a shell script or from Perl?
If from Perl, you should not call a nested Perl interpreter at all.
If the file is small, slurp it in and print:
use File::Slurp;
my #lines = read_file($filename);
write_file($filename, grep { ! /^$id$/ } #lines);
If the file is large, read line by line as a filter.
use File::Copy;
move($filename, "$filename.old") or die "Can not rename: $!\n";
open(my $fh_old, "<", "$filename.old") or die "Can not open $filename.old: $!\n";
open(my $fh, ">", $filename) or die "Can not open $filename: $!\n";
while my $line (<$fh_old>) {
next if $line =~ /^id$/;
print $fh $_;
}
close($fh_old);
close($fh);
If from a shell script, this worked for me:
$ cat x1
123456
234564
364899
437373
$ perl -n -i.bak -e "print unless /^$id$/" x1
$ cat x1
234564
364899
437373
if(-s $filetoopen){
perl -n -i.bak -e "print unless /^$id$,/" $filetoopen;
}
I'm not at all sure what you expect this to do. You can't just put a command line program in the middle of Perl code. You need to use system to call an external program. And Perl is just an external program like any other.
if(-s $filetoopen){
system('perl', '-n -i.bak -e "print unless /^$id$,/"', $filetoopen);
}
The functionality of the -i command line argument can be accessed via $^I.
local #ARGV = $filetoopen;
local $^I = '.bak';
local $_;
while (<>) {
print if !/^$id$/;
}