Can we create bash instance in perl script? - perl

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!".

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 in command line: perl -p -i -e "some text" /path

I am not familiar with perl. I am reading an installation guide atm and the following Linux command has come up:
perl -p -i -e "s/enforcing/disabled/" /etc/selinux/config
Now, I am trying to understand this. Here is my understanding so far:
-e simply allows for executing whatever follows
-p puts my commands that follow -e in a loop. Now this is strange to me, as to me this command seems to be trying to say: Write "s/enforcing/disabled/" into /etc/selinux/config. Then again, where is the "write" command? And what is this -i (inline) good for?
-p changes
s/enforcing/disabled/
to something equivalent to
while (<>) {
s/enforcing/disabled/;
print;
}
which is short for
while (defined( $_ = <ARGV> )) {
$_ =~ s/enforcing/disabled/;
print($_);
}
What this does:
It reads a line from ARGV into $_. ARGV is a special file handle that reads from the each of the files specified as arguments (or STDIN if no files are provided).
If EOF has been reached, the loop and therefore the program exits.
It replaces the first occurrence of enforcing with disabled.
It prints out the modified line to the default output handle. Because of -i, this is a handle to a new file with the same name as the one from which the program is currently reading.*
Repeat.
For example,
$ cat a
foo
bar enforcing the law
baz
enforcing enforcing
$ perl -pe's/enforcing/disabled/' -i a
$ cat a
foo
bar disabled the law
baz
disabled enforcing
* — In old versions of Perl, the old file has already been deleted at this point, but it's still accessible as long as there's an open file handle to it. In very new versions of Perl, this writes to temporary file that will later overwrite the file from which the program is reading.
To find out exactly what Perl is going to do, you can use the O module
perl -MO=Deparse -p -i -e "s/enforcing/disabled/" file
outputs
BEGIN { $^I = ""; }
LINE: while (defined($_ = readline ARGV)) {
s/enforcing/disabled/;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK

Executing grep via Perl

I am new to Perl. I am trying to execute grep command with perl.
I have to read input from a file and based on the input, the grep has to be executed.
My code is as follows:
#!/usr/bin/perl
use warnings;
use strict;
#Reading input files line by line
open FILE, "input.txt" or die $!;
my $lineno = 1;
while (<FILE>) {
print " $_";
#This is what expected.
#our $result=`grep -r Unable Satheesh > out.txt`;
our $result=`grep -r $_ Satheesh > out.txt`;
print $result
}
print "************************************************************\n";
But, if I run the script, it looks like a infinite loop and script is keep on waiting and nothing is printed in the out.txt file.
The reason it's hanging is because you forgot to use chomp after reading from FILE. So there's a newline at the end of $_, and it's executing two shell commands:
grep -r $_
Satheesh > out.txt
Since there's no filename argument to grep, it's reading from standard input, i.e. the terminal. If you type Ctl-d when it hangs, you'll then get an error message telling you that there's no Satheesh command.
Also, since you're redirecting the output of grep to out.txt, nothing gets put in $result. If you want to capture the output in a variable and also put it into the file, you can use the tee command.
Here's the fix:
while (<FILE>) {
print " $_";
chomp;
#This is what expected.
#our $result=`grep -r Unable Satheesh > out.txt`;
our $result=`grep -r $_ Satheesh | tee out.txt`;
print $result
}

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$/;
}