Is there a problem opening file names on the command line via $ _?

I had a problem with a script modification that processes files passed as command line arguments, just to copy these files, to further modify these files. The following perl script file worked fine for copying files:

use strict; use warnings; use File::Copy; foreach $_ (@ARGV) { my $orig = $_; (my $copy = $orig) =~ s/\.js$/_extjs4\.js/; copy($orig, $copy) or die(qq{failed to copy $orig -> $copy}); } 

Now that I have files called "* _extjs4.js", I would like to pass them to a script that similarly takes file names from the command line and processes the lines in these files. So far, I can successfully handle the file descriptor as follows in a script, and it displays on it:

 use strict; use warnings; foreach $_ (@ARGV) { print "$_\n"; open(my $fh, "+>", $_) or die $!; print $fh; #while (my $line = <$fh>) { # print $line; #} close $fh; } 

What outputs (partially):

 ./filetree_extjs4.js GLOB(0x1a457de8) ./async_submit_extjs4.js GLOB(0x1a457de8) 

What I really want to do, rather than print the file descriptor view, is to work with the contents of the files themselves. The start will be to print the lines of the files that I was trying to do with the crossed out code above.

But this code does not work, file lines are not printed. What am I doing wrong? Is there a conflict between $ _ used to process command line arguments and one used to process the contents of the file?

+4
source share
3 answers

There seem to be a few questions here.


What I really want to do, rather than print the file descriptor view, is to work with the contents of the files themselves.

The reason print $fh returns GLOB(0x1a457de8) is because the $fh scalar is a file descriptor, not the contents of the file itself. To access the contents of the file itself, use <$fh> . For instance:

 while (my $line = <$fh>) { print $line; } # or simply print while <$fh>; 

prints the contents of the entire file.

This is described in pelrdoc perlop :

If what the angle brackets contain is a simple scalar variable (for example, <$foo> ), then this variable contains the file descriptor name for the input or its type global or a reference to the same.


But it has already been tested!

I see it. Try changing the opening mode to +< .

According to perldoc perlfaq5 :

How is it that when I open a file for reading and writing, it wipes it?

Because you are using something like this, which truncates the file then gives you read and write access:

  open my $fh, '+>', '/path/name'; # WRONG (almost always) 

Oops Instead, you should use this to fail if the file does not exist:

  open my $fh, '+<', '/path/name'; # open for update 

Using ">" always clobbers or creates. Using "<" will never be. "+" does not change this.

It goes without saying that < or die $! recommended or die $! after open .


But take a step back.

There is a more Perlish way to back up the source file and then manipulate it. In fact, this can be done using the command line itself (!), Using the -i flag:

 $ perl -p -i._extjs4 -e 's/foo/bar/g' *.js 

See perldoc perlrun .


I cannot satisfy my command line needs.

If the manipulation is too large to process the command line, Tie::File worth it.

+6
source

To read the contents of a file descriptor, you must call readline read or place the file descriptor in angle brackets <> .

 my $line = readline $fh; my $actually_read = read $fh, $text, $bytes; my $line = <$fh>; # similar to readline 

To print to a file descriptor other than STDIN , you must have it as the first argument to print , followed by what you want to print, without a comma between them.

 print $fh 'something'; 

So that someone does not accidentally add a comma, I prefer to put the file descriptor in a block.

 print {$fh} 'something'; 

You can also select your new descriptor.

 { my $oldfh = select $fh; print 'something'; select $oldfh; # reset it back to the previous handle } 

Also, the mode argument to open causes it to compress the contents of the file. There is nothing to read at this moment.

Try this instead:

 open my $fh, '+<', $_ or die; 
+1
source

I would like to add something to Zaid's wonderful suggestion for using a single-line interface.

When you are new to perl and trying to use some complex regular expressions, it might be nice to use the source file for them, since overcrowding can occur on the command line. I.e:.

File:

 #!/usr/bin/perl use warnings; use strict; s/complicated/regex/g; 

When setting up a regular expression, use the source file as follows:

 perl -p script.pl input.js perl -p script.pl input.js > testfile perl -p script.pl input.js | less 

Note that when testing you do not use the -i flag. These commands will not change the input files, just print the changes in standard mode.

When you are ready to make (permanent!) Changes, just add the edit flag in place of -i and, if you want (recommended), put the extension for backups, for example. ".bak".

 perl -pi.bak script.pl *.js 
0
source

Source: https://habr.com/ru/post/1386925/


All Articles