Perl reflex query

  • Thread starter Thread starter Deleted member 49549
  • Start date Start date
D

Deleted member 49549

Guest
hi all. Looking for some perl experts. I have the following script that inserts the file name in the first line of a text file. However, it doesn't work if there are any spaces in the filename. Any ideas?

perl -i -pe 'BEGIN{undef $/;} s/^/$ARGV\n/' `find . -name '*.txt'`
 
I suspect its the $ARGV taking the space as two separate arguments. It is an array of command line arguments (or the file name if none specified), so you will then be trying to edit a filename truncated at the first space
 
I wonder if using find as follows will play nicer?

find . -name *.txt -exec command {} \;

If I've got time tonight I'll have a little play ... I've been meaning to learn the basics of perl scripting anyway...

On Edit:

This is getting close, although I've not quite sussed iterating through subdirectories yet...

Code:
#!/usr/bin/perl
use strict;
use warnings;

my $dir = '.' ;
opendir(DIR, $dir) or die $!; 

while (my $file = readdir(DIR)) {
  
  next unless ($file =~ m/\.txt$/);

  open my $in,  '<', $file or die "Can't read file: $!" ;
  open my $out, '>', "$file.new" or die "Can't write new file: $!" ;

  print $out "$file\n" ;

  while( <$in> )
  {
    print $out $_ ;
  }

  close $out ;
  rename "$file.new",$file;
}

closedir(DIR);
exit 0;

Saved as nobble.pl ...

Code:
afasoas@cinelli ~/temp $ ./nobble.pl
foo bar.txt
foo.txt
bar.txt
afasoas@cinelli ~/temp $ cat foo.txt
foo.txt
afasoas@cinelli ~/temp $ cat foo\ bar.txt
foo bar.txt
 
Last edited:
Sort of works!

But replaces the text in the file with the filename, rather than insert.
 
What are you aiming to achieve? Just add a list of filenames to a file?

Code:
find . -name "*.txt" >> mylistoffiles.txt

if you don't want the directory entries then,

Code:
find . -name "*.txt" -exec basename {} \; >> mylistoffiles.txt

No perl required?
 
Last edited:
Hi Tony, i have a directory of text files, but wish to insert the filename as the first line of each text file. (even better if i can get the filename prefixed with #)
 
Ah, okay.

Code:
for file in $(find . -name "*.txt")
do
   echo "#$(basename $file)" | cat - "$file" > temp && mv temp "$file"
done

This will keep creating a file called temp so make sure it doesn't exist already. Also, test this somewhere first.

edit: hmm, doesn't work with spaces in filenames.
 
Last edited:
Edited version:

Code:
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;

sub processFile{
    my $file = $_; 
    next unless ($file =~ m/\.txt$/);

    open my $in,  '<', $file or die "Can't read file: $!" ;
    open my $out, '>', "$file.new" or die "Can't write new file: $!" ;

    print $out "$file\n" ;

    while( <$in> )
    {   
      print $out $_ ;
    }   

    close $out ;
    rename "$file.new",$file
}

my $dir = '/home/afasoas/temp' ;
find(\&processFile, $dir) ;
exit 0;

STILL doesn't iterate through sub-directories, but I think I'll have it cracked soonish using file::find.
DISCLAIMER: NOT a perl expert.

Will have another stab when I get home.
 
Last edited:
That’s working great, thanks Tony.

How would i edit that to exclude the suffix of the file (in all cases this is .txt) and to add a blank line following the inserted filename?
 
On Edit: I know it's not as eloquent as some solutions, but this now does what you want - iterates through the file system, picking up every $file.txt and prepends "# $file\n\n" (without the .txt suffice) as the first line.

Code:
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;

sub processFile{
    my $file = $_; 
    return unless ($file =~ m/\.txt$/);

    open my $in,  '<', $file or die "Can't read file: $!" ;
    open my $out, '>', "$file.new" or die "Can't write new file: $!" ;

    print $out ("#$file\n\n" =~ s/.txt//r ) ;

    while( <$in> )
    {   
      print $out $_ ;
    }   

    close $out ;
    rename "$file.new",$file
}

my $dir = '/home/afasoas/temp' ;
find(\&processFile, $dir) ;
exit 0;
 
Last edited:
On Edit: I know it's not as eloquent as some solutions, but this now does what you want - iterates through the file system, picking up every $file.txt and prepends "# $file\n\n" (without the .txt suffice) as the first line.

Code:
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;

sub processFile{
    my $file = $_;
    return unless ($file =~ m/\.txt$/);

    open my $in,  '<', $file or die "Can't read file: $!" ;
    open my $out, '>', "$file.new" or die "Can't write new file: $!" ;

    print $out ("#$file\n\n" =~ s/.txt//r ) ;

    while( <$in> )
    {  
      print $out $_ ;
    }  

    close $out ;
    rename "$file.new",$file
}

my $dir = '/home/afasoas/temp' ;
find(\&processFile, $dir) ;
exit 0;

Hi afasoas - that script replaces the text in the file with the filename, rather than insert.
 
Ah, this works.

Code:
IFS=$'\n'; for file in $(find . -name "*.txt"); do  echo "#$(basename $file)" | cat - "$file" > temp && mv temp "$file"; done

again, test somewhere safe :)

Hi @EightBitTony,

How would i edit that to exclude the suffix of the file (in all cases this is .txt) and to add a blank line following the inserted filename?
 
Hi afasoas - that script replaces the text in the file with the filename, rather than insert.

An earlier version I put up did, but not the current version which is the one you quoted.
You can see it's creating a new temporary file, printing the header to the newfile, and then printing the old file to the new file.
It then renames the new file to replace the old file.

In the previous version, I was defining the new file and the old file as the same file... which didn't work.

I'm now using a perl script loosely based on this one to update my bind restricted policy zone with spam and advertising domains that should be redirected, in effect running an adblocker for my home network.
 
An earlier version I put up did, but not the current version which is the one you quoted.
You can see it's creating a new temporary file, printing the header to the newfile, and then printing the old file to the new file.
It then renames the new file to replace the old file.

In the previous version, I was defining the new file and the old file as the same file... which didn't work.

I'm now using a perl script loosely based on this one to update my bind restricted policy zone with spam and advertising domains that should be redirected, in effect running an adblocker for my home network.

My mistake, i was running there older version...

EDIT

All working great. Thank you very much afasoas
 
Last edited by a moderator:
I notice it's not displaying properly within the code block in my original post, yet when I edit the post, the script is there in all it's fullness.
Must need some escape characters???


#!/usr/bin/perl
use strict;
use warnings;
use File::Find;

sub processFile{
my $file = $_;
return unless ($file =~ m/\.txt$/);

open my $in, '<', $file or die "Can't read file: $!" ;
open my $out, '>', "$file.new" or die "Can't write new file: $!" ;

print $out ("#$file\n\n" =~ s/.txt//r ) ;

while( <$in> )
{
print $out $_ ;
}

close $out ;
rename "$file.new",$file
}

my $dir = '/home/afasoas/temp' ;
find(\&processFile, $dir) ;
exit 0;
 
Back
Top