How delete extension in a perl script - perl

A silly question, but it make me crazy!
I have a script to remove "fat" data in a bvh file. (Biovision mocap file..).
Works fine, but it create a double extension... (The name.bvh.bvh)
I just only need one extension (*.bvh, not the *.bvh.bvh!!!)
Here is the code:
#files = <*.bvh>;
foreach $file (#files) {
open (OLD, $file) || die "Couldn´t open $file: $!\n";
open (NEW, ">$file.bvh") || die "Couldn´t open $file.bvh: $!\n";
while (<OLD>) {
$line = $_;
if (/Normal/) { while (<OLD>) { last if /}/; } $line => ""; }
if (/normalIndex/) { while(<OLD>) { last if /[]]/; } $line = ""; }
$line =~ s/[-+]?[0-9]\.[0-9]+e[+-][0-9]+/0/g;
$line =~ s/([-+]?[0-9]+\.[0-9]{2})[0-9]+/$1/g;
$line =~ s/0\.00/0/g;
$line =~ s/[ ]+/ /g;
$line =~ s/[\t]+/ /g;
$line =~ s/^ //g;
print NEW $line;
}
close OLD;
unlink ($file);
close NEW;
}
Any help? Thanks!

#files = <*.bvh>;
This gives you a list of the files that have a .bvh extension. So it will end up containing something like:
('foo.bvh', 'bar.bvh', 'baz.bvh')
Then you walk the array with this code:
foreach $file (#files) {
...
}
Each time round this loop, $file will contain a value from your array. One the first iteration, for example, $file will contain foo.bvh.
Then you open input and output files:
open (OLD, $file) || die "Couldn´t open $file: $!\n";
open (NEW, ">$file.bvh") || die "Couldn´t open $file.bvh: $!\n";
As $file contains foo.bvh, your new file (which is created using the name "$file.bvh") will be called foo.bvh.bvh.
The naive fix would be to remove the .bvh from the open() statement:
# DON'T DO THIS
open (OLD, $file) || die "Couldn´t open $file: $!\n";
open (NEW, ">$file") || die "Couldn´t open $file.bvh: $!\n";
This won't work as your old and new files will now have the same name and when you open your new file for writing, it will truncate the file and remove all of your input data.
You'll need to rename a file at some point. And the easiest approach is to keep your existing filenames and once you have processed each file, rename it to the original name.
# And then at the end of your loop
# Note that as you're copying the new file over the old one,
# there's no need to delete the old one.
close OLD;
close NEW;
rename("$file.bvh", $file);

Just insert rename("$file.new", $file);
as shown in your code:
#files = <*.bvh>;
foreach $file (#files) {
open (OLD, $file) || die "Couldn´t open $file: $!\n";
open (NEW, ">$file.new") || die "Couldn´t open $file.new: $!\n";
while (<OLD>) {
$line = $_;
if (/Normal/) { while (<OLD>) { last if /}/; } $line => ""; }
if (/normalIndex/) { while(<OLD>) { last if /[]]/; } $line = ""; }
$line =~ s/[-+]?[0-9]\.[0-9]+e[+-][0-9]+/0/g;
$line =~ s/([-+]?[0-9]+\.[0-9]{2})[0-9]+/$1/g;
$line =~ s/0\.00/0/g;
$line =~ s/[ ]+/ /g;
$line =~ s/[\t]+/ /g;
$line =~ s/^ //g;
print NEW $line;
}
close OLD;
unlink ($file);
close NEW;
rename("$file.new", $file);
}

I am sure this is not the way however you can get the output.
Use this Module for renaming function
use File::Copy;
#files = qw(first.bhv second.bhv third.bhv);
foreach $file (#files) {
Just remove the extension on the original file
(my $rem_ext = $file)=~s/\.bhv$//;
rename the file without extension
rename($file, $rem_ext);
Just read the without extension file
open (OLD, $rem_ext) || die "Couldn´t open $rem_ext: $!\n";
open (NEW, ">$file") || die "Couldn´t open $file.bvh: $!\n";
while (<OLD>) {
...
}
close OLD;
Delete the files without extension which is created by ourself.
unlink($rem_ext);
close NEW;
}
It will works

Related

Nested if statements: Swapping headers and sequences in fasta files

I am opening a directory and processing each file. A sample file looks like this when opened:
>AAAAA
TTTTTTTTTTTAAAAATTTTTTTTTT
>BBBBB
TTTTTTTTTTTTTTTTTTBBBBBTTT
>CCCCC
TTTTTTTTTTTTTTTTCCCCCTTTTT
For the above sample file, I am trying to make them look like this:
>TAAAAAT
AAAAA
>TBBBBBT
BBBBB
>TCCCCCT
CCCCC
I need to find the "header" in next line sequence, take flanks on either side of the match, and then flip them. I want to print each file's worth of contents to another separate file.
Here is my code so far. It runs without errors, but doesn't generate any output. My guess is this is probably related to the nested if statements. I have never worked with those before.
#!/usr/bin/perl
use strict;
use warnings;
my ($directory) = #ARGV;
my $dir = "$directory";
my #ArrayofFiles = glob "$dir/*";
my $count = 0;
open(OUT, ">", "/path/to/output_$count.txt") or die $!;
foreach my $file(#ArrayofFiles){
open(my $fastas, $file) or die $!;
while (my $line = <$fastas>){
$count++;
if ($line =~ m/(^>)([a-z]{5})/i){
my $header = $2;
if ($line !~ /^>/){
my $sequence .= $line;
if ($sequence =~ m/(([a-z]{1})($header)([a-z]{1}))/i){
my $matchplusflanks = $1;
print OUT ">", $matchplusflanks, "\n", $header, "\n";
}
}
}
}
}
How can I fix this code? Thanks.
Try this
foreach my $file(#ArrayofFiles)
{
open my $fh," <", $file or die"error opening $!\n";
while(my $head=<$fh>)
{
chomp $head;
$head=~s/>//;
my $next_line = <$fh>;
my($extract) = $next_line =~m/(.$head.)/;
print ">$extract\n$head\n";
}
}
There are several mistakes in your code but the main problem is:
if ($line =~ m/(^>)([a-z]{5})/i) {
my $header = $2;
if ($line !~ /^>/) {
# here you write to the output file
Because the same line can't start and not start with > at the same time, your output files are never written. The second if statement always fails and its block is never executed.
open(OUT, ">", "/path/to/output_$count.txt") or die $!; and $count++ are misplaced. Since you want to produce an output file (with a new name) for each input file, you need to put them in the foreach block, not outside or in the while loop.
Example:
#!/usr/bin/perl
use strict;
use warnings;
my ($dir) = #ARGV;
my #files = glob "$dir/*";
my $count;
my $format = ">%s\n%s\n";
foreach my $file (#files) {
open my $fhi, '<', $file
or die "Can't open file '$file': $!";
$count++;
my $output_path = "/path/to/output_$count.txt";
open my $fho, '>', $output_path
or die "Can't open file '$output_path': $!";
my ($header, $seq);
while(<$fhi>) {
chomp;
if (/^>([a-z]{5})/i) {
if ($seq) { printf $fho $format, $seq =~ /([a-z]$header[a-z])/i, $header; }
($header, $seq) = ($1, '');
} else { $seq .= $_; }
}
if ($seq) { printf $fho $format, $seq =~ /([a-z]$header[a-z])/i, $header; }
}
close $fhi;
close $fho;

File editing in perl

Hi I am trying to delete a content of file based on regex match. Here is the following code:
my $file = "Cioin_PatchAnalysis.txt";
local $/ = 'Query=';
my #content = ();
open (INFILE, $file) || die "error2: $!";
while (<INFILE>)
{
chomp;
if ($_ =~ /\s*3374_Cioin/)
{#capture the query sequence
#content = $_;
print #content;
}
}
Sample data is:
===================================================================
Query= 3374_Cioin
(24,267 letters)
Database: /home/aprasanna/BLAST/DMel_renamedfile.fasta
14,047 sequences; 7,593,731 total letters
Reference: Altschul, Stephen F., Thomas L. Madden, Alejandro A. Schaffer,
Jinghui Zhang, Zheng Zhang, Webb Miller, and David J. Lipman (1997),
"Gapped BLAST and PSI-BLAST: a new generation of protein database search
programs", Nucleic Acids Res. 25:3389-3402.
Query= 578_Antlo
(88 letters)
=========================================================
I wish to remove from Query =3374_Coin... till -3402. i.e till next record separator. I am able to store the matched part in #content. However, I am not able to delete it in the original file. I wish my original file only has Query= 578_Antlo!
I am very new to Perl.
The easiest way is to simply write all lines you do want into some other file.
I would suggest something like:
my $file = "Cioin_PatchAnalysis.txt";
my $outfile = "Fixed_Cioin_PatchAnalysis.txt";
local $/ = 'Query=';
my #content = ();
open (INFILE, $file) || die "error2: $!";
open(my $outfile, '>', $outfile) or die "Could not open file '$outfile' $!";
while (<INFILE>)
{
chomp;
if ($_ !~ /\s*3374_Cioin/)
{#capture the query sequence
#content = $_;
print $outfile #content;
}
}
Than you can replace the original with the new file.
Another option is to keep all the lines that doesn't match the regex, than print them back into the original file:
my $file = "Cioin_PatchAnalysis.txt";
local $/ = 'Query=';
my #content = ();
open (INFILE, $file) || die "error2: $!";
while (<INFILE>)
{
chomp;
if ($_ !~ /\s*3374_Cioin/)
{#capture the query sequence
push #content, $_;
}
}
open(my $outfile, '>', $file) or die "Could not open file '$outfile' $!";
print $outfile #content;

Combining two csv files together in perl

Hi i'm very new to perl and i've got litle knowledge on it but i'm trying to create a script that conbines two .csv files into a new one
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV_XS;
my #rows;
{ # Read the CSV file
my $csv = Text::CSV_XS->new() or die "Cannot use Text::CSV_XS ($!)";
my $file = "file.csv";
open my $fh, '<', $file or die "Cannot open $file ($!)";
while (my $row = $csv->getline($fh)) {
push #rows, $row;
}
$csv->eof or $csv->error_diag();
close $fh or die "Failed to close $file ($!)";
}
{ # Gather the data
foreach my $row (#rows) {
foreach my $col (#{$row}) {
$col = uc($col);
}
print "\n";
}
}
# (over)Write the data
# Needs to be changed to ADD data
{
my $csv = Text::CSV_XS->new({ binary => 1, escape_char => undef })
or die "Cannot use Text::CSV ($!)";
my $file = "output.csv";
open my $fh, '>', $file or die "Cannot open $file ($!)";
$csv->eol("\n");
foreach my $row (#rows) {
$csv->print($fh, \#{$row}) or die "Failed to write $file ($!)";
}
close $fh or die "Failed to close $file ($!)";
}
this is my current code i do know this over write's the data insted of actually adding it to the new file but this is how far i managed to get with the limited time and knowledge i've got on perl
the csv format of both files are the same.
"Header1";"Header2";"Header3";"Header4";"Header5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
"Data1";"Data2";"Data3";"Data4";"Data5"
I believe the issue is here:
open my $fh, '>', $file
or die "Cannot open $file ($!)";
If I remember my Perl properly, the line should read:
open my $fh, '>>', $file
or die "Cannot open $file ($!)";
The >> should open the file handle $fh for append instead of for overwrite.
you could try something like this
opendir(hand,"DIRPATH");
#files = readdir(hand);
closedir(hand);
foreach(#files){
if(/\.csv$/i) { #if the filename has .csv at the end
push(#csvfiles,$_);
}
}
foreach(#csvfiles) {
$csvfile=$_;
open(hanr,"DIRPATH".$csvfile)or die"error $!\n"; #read handler
open(hanw , ">>DIRPATH"."outputfile.csv") or die"error $! \n"; #write handler for creating new sorted files
#lines=();
#lines=<hanr>;
foreach $line (#lines){
chomp $line;
$count++;
next unless $count; # skip header i.e the first line containing stock details
print hanw join $line,"\n";
}
$count= -1;
close(hanw);
close(hanr);
}`

To replace a string and append a string in perl in 1 file

I want to replace a line in my file and after replacing it I want to append another line. As you can see here, I have to open and close files for 2 times. Can I do it by opening a file only once? Thanks
use strict;
use warnings;
open(FILE,"tmp1.txt") || die "Can't open file: $!";
undef $/;
my $file = <FILE>;
my #lines = <FILE>;
my #newlines;
for each(#lines) {
$_ =~ s/hello/hi/g;
push(#newlines,$_);
}
close(FILE);
open(FILE, "> tmp1.txt ") || die "File not found";
print FILE #newlines;
close(FILE);
open(FILE,"tmp1.txt") || die "Can't open file: $!";
undef $/;
my $file = <FILE>;
my #lines = <FILE>;
my $first_line = "hi";
my $second_line = "sun";
my $insert = "good morning";
$file =~ s/\Q$first_line\E\n\Q$second_line\E/$first_line\n$insert\n$second_line/;
open(OUTPUT,"> tmp3.txt") || die "Can't open file: $!";
print OUTPUT $file;
close(OUTPUT);
Use Three-arg open and open your file in Read+Write mode by +<.

merging two files using perl keeping the copy of original file in other file

I have to files like A.ini and B.ini ,I want to merge both the files in A.ini
examples of files:
A.ini::
a=123
b=xyx
c=434
B.ini contains:
a=abc
m=shank
n=paul
my output in files A.ini should be like
a=123abc
b=xyx
c=434
m=shank
n=paul
I want to this merging to be done in perl language and I want to keep the copy of old A.ini file at some other place to use old copy
A command line variant:
perl -lne '
($a, $b) = split /=/;
$v{$a} = $v{$a} ? $v{$a} . $b : $_;
END {
print $v{$_} for sort keys %v
}' A.ini B.ini >NEW.ini
How about:
#!/usr/bin/perl
use strict;
use warnings;
my %out;
my $file = 'path/to/A.ini';
open my $fh, '<', $file or die "unable to open '$file' for reading: $!";
while(<$fh>) {
chomp;
my ($key, $val) = split /=/;
$out{$key} = $val;
}
close $fh;
$file = 'path/to/B.ini';
open my $fh, '<', $file or die "unable to open '$file' for reading: $!";
while(<$fh>) {
chomp;
my ($key, $val) = split /=/;
if (exists $out{$key}) {
$out{$key} .= $val;
} else {
$out{$key} = $val;
}
}
close $fh;
$file = 'path/to/A.ini';
open my $fh, '>', $file or die "unable to open '$file' for writing: $!";
foreach(keys %out) {
print $fh $_,'=',$out{$_},"\n";
}
close $fh;
The two files to be merged can be read in a single pass and don't need to be treated as separate source files. That allows the use of <> to read all files passed as parameters on the command line.
Keeping a backup copy of A.ini is simply a matter of renaming it before writing the merged data to a new file of the same name.
This program appears to do what you need.
use strict;
use warnings;
my $file_a = $ARGV[0];
my (#keys, %values);
while (<>) {
if (/\A\s*(.+?)\s*=\s*(.+?)\s*\z/) {
push #keys, $1 unless exists $values{$1};
$values{$1} .= $2;
}
}
rename $file_a, "$file_a.bak" or die qq(Unable to rename "$file_a": $!);
open my $fh, '>', $file_a or die qq(Unable to open "$file_a" for output: $!);
printf $fh "%s=%s\n", $_, $values{$_} for #keys;
output (in A.ini)
a=123abc
b=xyx
c=434
m=shank
n=paul