Yes I know maybe the title is not very clear. If you have suggestions about changing it, please tell me.
This is my problem:
I have one file (we call it File_1) where there are several lines, each one is a sentence.
For ex:
File_1 content:
*Line 1*: I'm very happy today.
*Line 2*: We're going to the cinema.
*Line 3*: I'll write on stackoverflow today!
And so on..
My question is, how can I create several files from the content of each line?
So for ex. file_1 will be splitted into:
*Line_1_content.txt* : I'm very happy today.
*Line_2_content.txt* : We're going to the cinema.
And so on...
I don't know how to do, really. I've never faced this kind of problem.
I will appreciate your help.
use strict;
use warnings;
use autodie;
while ( <> ) {
open my $fh, '>', "${.}.txt";
print $fh $_;
}
$. corresponds to the number of the current line.
You call this program like this: perl prog.pl your_file
If I understand correctly the question something line:
use strict;
use warnings;
use autodie;
open(my $fh, '<', 'example.txt');
while (my $line = <$fh>) {
open(my $line_fh, '>', "line_${.}_file.txt");
print $line_fh $line;
close($line_fh);
}
close($fh);
Should do what you want.
(Although doing this maybe doesn't make a lot of sense like the comments point out)
You don't even need a program :-)
perl -ne 'open my $fh, ">", "Line_${.}_content.txt"; print $fh $_"' your_file_here
Or, perhaps,
perl -pe 'open my $fh, ">", "Line_${.}_content.txt"; select $fh' your_file_here
Related
i try to import huge text file (~5 million lines). I try with this script
aaa = perl('importFile.pl',fileName);
where "importFile.pl" is
use strict;
use warnings;
while (my $row = <>) {
chomp $row;
print "$row\n";
}
but nothing happens!. what is my mistake??? Or can you suggest similar (and fast) solution?
Matlab R2014a 64bit
Iam not super familiar with perl but have worked with it alittle in the past.I'm guessing there is an issue with your loop, but like I stated i'm not a perl monk! Here is a program I used to read from a file and prints it:
#!/usr/bin/perl
use strict;
use warnings;
#Opens a file handler
open my $fh, '<', '/home/user/Desktop/ScriptForChangesets/ToBeRead.txt' or die "Can't open file";
#Prints the file contents
print do{local $/; <$fh>};
Hope this helps!
I'm completely new to Perl and I thought that would be the best language to solve my simple task. I need to convert a binary file into something readable and need to find and replace strings like \x00\x39 into \x09 (tab) or something like that.
From bash, I started with the following and it works great:
perl -pi -e 's/abc/123/g' test.txt
However, when I start to enter ascii codes, I'm lost:
perl -pi -e 's/0x49/*/g' test.txt
perl -pi -e 's/{char(49)}/*/g' test.txt
How would this command would look like as a line in a perl script? I have about a couple hundred of these find/replacement operations and a 500MB text file. Are there any caveats that I would need to know?
Thanks so much for any help!
Gary
Use the \x## notation:
perl -pi~ -e 's/\x00/*/g' test.txt
To replace each "special" character with its code in brackets, use the /e option:
perl -pi~ -e 's/([\x0-\x09\x11-\x1f])/"[" . ord($1) . "]"/eg' test.txt
Wow, thank you very much. I learned that it wasn't as easy as I assumed. Wow, Perl is truly very complex ;-)
Here is, what I came up with. I hope this will help someone.
BTW: If you have any chance to know if this will also work on Windows Perl, please let me know.
Thanks again,
Gary
#!/usr/bin/perl
use strict;
use warnings;
my $infile = '/Users/gc/Desktop/a.bin';
my $outfile = '/Users/gc/Desktop/b.txt'; # in and out can be the same file; file will be overwritten when it already exists
my $data = read_file($infile);
# 1st batch
$data =~ s/0\x01J[\x00-\x19]/\x09AnythingYouWant\x09/g;
$data =~ s/0\x00[\x00-\x19]/\x09AnythingYouWant\x09/g;
# 2nd batch
$data =~ s/\r/\x06/g; # CR into \x06
$data =~ s/\n/\x06/g; # LF into \x06
$data =~ s/\r\n/\x06/g; # CR LF into \x06
# …
write_file($outfile, $data);
exit;
sub read_file {
my ($infile) = #_;
open my $in, '<', $infile or die "Could not open '$infile' for reading $!";
local $/ = undef;
my $all = <$in>;
close $in;
return $all;
}
sub write_file {
my ($outfile, $content) = #_;
open my $out, '>', $outfile or die "Could not open '$outfile' for writing $!";;
print $out $content;
close $out;
return;
}
Although it's a bit weird to do string replaces on a binary file, here's how to do it with your txt file:
use strict;
use warnings;
use Tie::File;
my #file;
tie #file, 'Tie::File', 'test.txt' or die $!;
foreach (#file) {
# your regexes go here
s/abc/123/g;
s/\0x49/*/g;
}
untie #file;
The Tie::File module (from the Perl core) allows you to access the lines of the file through an array. Changes will be saved to the file immediately. In the foreach loop, the file is processed line by line. The lines go into $_, which we cannot see. The regex operations are by default also applied to $_, so there's no need to write it down.
However, I believe you are going about this the wrong way. In most cases, you will not be able to just read the file line by line. Refer to perlfaq as a starting point. Dealing with binary is somewhat more tricky than just text processing I'm afraid.
I'm trying to read in this file:
Oranges
Apples
Bananas
Mangos
using this:
open (FL, "fruits");
#fruits
while(<FL>){
chomp($_);
push(#fruits,$_);
}
print #fruits;
But I'm not getting any output. What am I missing here? I'm trying to store all the lines in the file into an array, and printing out all the contents on a single line. Why isn't chomp removing the newlines from the file, like it's supposed to?
you should always use :
use strict;
use warnings;
at the begining of your scripts.
and use 3 args open, lexical handles and test opening for failure, so your script becomes:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #fruits;
my $file = 'fruits';
open my $fh, '<', $file or die "unable to open '$file' for reading :$!";
while(my $line = <$fh>){
chomp($line);
push #fruits, $line;
}
print Dumper \#fruits;
I'm guessing that you have DOS-style newlines (i.e., \r\n) in your fruits file. The chomp command normally only works on unix-style (i.e., \n.)
You're not opening any file. FL is a file handle that never is opened, and therefore you can't read from it.
The first thing you need to do is put use warnings at the top of your program to help you with these problems.
#!/usr/bin/env perl
use strict;
use warnings;
use IO::File;
use Data::Dumper;
my $fh = IO::File->new('fruits', 'r') or die "$!\n";
my #fruits = grep {s/\n//} $fh->getlines;
print Dumper \#fruits;
that's nice and clean
You should check open for errors:
open( my $FL, '<', 'fruits' ) or die $!;
while(<$FL>) {
...
1) You should always print the errors from IO. `open() or die "Can't open file $f, $!";
2) you probably started the program from different directory from where file "fruits" is
Currently I am using
system("echo $panel_login $panel_password $root_name $root_pass $port $panel_type >> /home/shared/ftp");
What is the easiest way to do the same thing using Perl? IE: a one-liner.
Why does it need to be one line? You're not paying by the line, are you? This is probably too verbose, but it took a total of two minutes to type it out.
#!/usr/bin/env perl
use strict;
use warnings;
my #values = qw/user secret-password ftp-address/;
open my $fh, '>>', 'ftp-stuff' # Three argument form of open; lexical filehandle
or die "Can't open [ftp-stuff]: $!"; # Always check that the open call worked
print $fh "#values\n"; # Quote the array and you get spaces between items for free
close $fh or die "Can't close [ftp-stuff]: $!";
You might find IO::All to be helpful:
use IO::All;
#stuff happens to set the variables
io("/home/shared/ftp")->write("$panel_login $panel_password $root_name $root_pass $port $panel_type");
EDIT (By popular and editable demand)
http://perldoc.perl.org/functions/open.html
In your case you would have to :
#21st century perl.
my $handle;
open ($handle,'>>','/home/shared/ftp') or die("Cant open /home/shared/ftp");
print $handle "$panel_login $panel_password $root_name $root_pass $port $panel_type";
close ($handle) or die ("Unable to close /home/shared/ftp");
Alternatively, you could use the autodie pragma (as #Chas Owens suggested in comments).
This way, no check (the or die(...)) part needs to be used.
Hope to get it right this time. If so, will erase this Warning.
Old deprecated way
Use print (not one liner though). Just open your file before and get a handle.
open (MYFILE,'>>/home/shared/ftp');
print MYFILE "$panel_login $panel_password $root_name $root_pass $port $panel_type";
close (MYFILE);
http://perl.about.com/od/perltutorials/a/readwritefiles_2.htm
You might want to use the simple File::Slurp module:
use File::Slurp;
append_file("/home/shared/ftp",
"$panel_login $panel_password $root_name $root_pass ".
"$port $panel_type\n");
It's not a core module though, so you'll have to install it.
(open my $FH, ">", "${filename}" and print $FH "Hello World" and close $FH)
or die ("Couldn't output to file: ${filename}: $!\n");
Of course, it's impossible to do proper error checking in a one liner... That should be written slightly differently:
open my $FH, ">", "${filename}" or die("Can't open file: ${filename}: $!\n");
print $FH "Hello World";
close $FH;
For advanced one-liners like this, you could also use the psh command from Psh, a simple pure Perl shell.
psh -c '{my $var = "something"; print $var} >/tmp/out.txt'
I use FileHandle. From the POD:
use FileHandle;
$fh = new FileHandle ">> FOO"; # modified slightly from the POD, to append
if (defined $fh) {
print $fh "bar\n";
$fh->close;
}
If you want something closer to a "one-liner," you can do this:
use FileHandle;
my $fh = FileHandle->new( '>> FOO' ) || die $!;
$fh->print( "bar\n" );
## $fh closes when it goes out of scope
You can do a one-liner like this one:
print "$panel_login $panel_password $root_name $root_pass $port $panel_type" >> io('/home/shared/ftp');
You only need to add the IO::All module to your code, like this:
use IO::All;
Some good reading about editing files with perl:
FMTYEWTK About Mass Edits In Perl
Yes, There's More Than One Way To Do It but there must be a canonical or most efficient or most concise way. I'll add answers I know of and see what percolates to the top.
To be clear, the question is how best to read the contents of a file into a string.
One solution per answer.
How about this:
use File::Slurp;
my $text = read_file($filename);
ETA: note Bug #83126 for File-Slurp: Security hole with encoding(UTF-8). I now recommend using File::Slurper (disclaimer: I wrote it), also because it has better defaults around encodings:
use File::Slurper 'read_text';
my $text = read_text($filename);
or Path::Tiny:
use Path::Tiny;
path($filename)->slurp_utf8;
I like doing this with a do block in which I localize #ARGV so I can use the diamond operator to do the file magic for me.
my $contents = do { local(#ARGV, $/) = $file; <> };
If you need this to be a bit more robust, you can easily turn this into a subroutine.
If you need something really robust that handles all sorts of special cases, use File::Slurp. Even if you aren't going to use it, take a look at the source to see all the wacky situations it has to handle. File::Slurp has a big security problem that doesn't look to have a solution. Part of this is its failure to properly handle encodings. Even my quick answer has that problem. If you need to handle the encoding (maybe because you don't make everything UTF-8 by default), this expands to:
my $contents = do {
open my $fh, '<:encoding(UTF-8)', $file or die '...';
local $/;
<$fh>;
};
If you don't need to change the file, you might be able to use File::Map.
In writing File::Slurp (which is the best way), Uri Guttman did a lot of research in the many ways of slurping and which is most efficient. He wrote down his findings here and incorporated them info File::Slurp.
open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);
Things to think about (especially when compared with other solutions):
Lexical filehandles
Reduce scope
Reduce magic
So I get:
my $contents = do {
local $/;
open my $fh, $filename or die "Can't open $filename: $!";
<$fh>
};
I'm not a big fan of magic <> except when actually using magic <>. Instead of faking it out, why not just use the open call directly? It's not much more work, and is explicit. (True magic <>, especially when handling "-", is far more work to perfectly emulate, but we aren't using it here anyway.)
mmap (Memory mapping) of strings may be useful when you:
Have very large strings, that you don't want to load into memory
Want a blindly fast initialisation (you get gradual I/O on access)
Have random or lazy access to the string.
May want to update the string, but are only extending it or replacing characters:
#!/usr/bin/perl
use warnings; use strict;
use IO::File;
use Sys::Mmap;
sub sip {
my $file_name = shift;
my $fh;
open ($fh, '+<', $file_name)
or die "Unable to open $file_name: $!";
my $str;
mmap($str, 0, PROT_READ|PROT_WRITE, MAP_SHARED, $fh)
or die "mmap failed: $!";
return $str;
}
my $str = sip('/tmp/words');
print substr($str, 100,20);
Update: May 2012
The following should be pretty well equivalent, after replacing Sys::Mmap with File::Map
#!/usr/bin/perl
use warnings; use strict;
use File::Map qw{map_file};
map_file(my $str => '/tmp/words', '+<');
print substr($str, 100, 20);
use Path::Class;
file('/some/path')->slurp;
{
open F, $filename or die "Can't read $filename: $!";
local $/; # enable slurp mode, locally.
$file = <F>;
close F;
}
This is neither fast, nor platform independent, and really evil, but it's short (and I've seen this in Larry Wall's code ;-):
my $contents = `cat $file`;
Kids, don't do that at home ;-).
use IO::All;
# read into a string (scalar context)
$contents = io($filename)->slurp;
# read all lines an array (array context)
#lines = io($filename)->slurp;
See the summary of Perl6::Slurp which is incredibly flexible and generally does the right thing with very little effort.
For one-liners you can usually use the -0 switch (with -n) to make perl read the whole file at once (if the file doesn't contain any null bytes):
perl -n0e 'print "content is in $_\n"' filename
If it's a binary file, you could use -0777:
perl -n0777e 'print length' filename
Here is a nice comparison of the most popular ways to do it:
http://poundcomment.wordpress.com/2009/08/02/perl-read-entire-file/
Nobody said anything about read or sysread, so here is a simple and fast way:
my $string;
{
open my $fh, '<', $file or die "Can't open $file: $!";
read $fh, $string, -s $file; # or sysread
close $fh;
}
Candidate for the worst way to do it! (See comment.)
open(F, $filename) or die "OPENING $filename: $!\n";
#lines = <F>;
close(F);
$string = join('', #lines);
Adjust the special record separator variable $/
undef $/;
open FH, '<', $filename or die "$!\n";
my $contents = <FH>;
close FH;