perl + add warn massage in perl one liner code

I have perl one liner code that rename the names of files/directories


find /tmp -name "*$NAME_THAT_WE_WANT_TO_CHANGE*" -exec /tmp/  's/\Q$ENV{NAME_THAT_WE_WANT_TO_CHANGE}\E/$1$ENV{NEW_NAME}$2/' {} +

I want to add print message ( warn ) , to my code in order to print which file/directory will be change

so I add the line:

       && warn "Rename file - [$ENV{$NAME_THAT_WE_WANT_TO_CHANGE}"'

so finaly the update code will be:

find /tmp -name "*$NAME_THAT_WE_WANT_TO_CHANGE*" -exec /tmp/  's/\Q$ENV{NAME_THAT_WE_WANT_TO_CHANGE}\E/$1$ENV{NEW_NAME}$2/ {} + && warn "Rename file - [$ENV{$NAME_THAT_WE_WANT_TO_CHANGE}"'

when I run the perl one liner I get the follwoing error message:

    find: missing argument to `-exec'

please advice what I need to fix/update in my code ?

. . . . .

full example ( before I add the warn "........." )

cd /tmp
touch orig-name
touch new-name
export NAME_THAT_WE_WANT_TO_CHANGE=orig-name
export NEW_NAME=new-name

find /tmp -name "*$NAME_THAT_WE_WANT_TO_CHANGE*" -exec /tmp/  's/\Q$ENV{NAME_THAT_WE_WANT_TO_CHANGE}\E/$1$ENV{NEW_NAME}$2/' {} +

ls | grep new-name

more /tmp/

# rename script examples from lwall:
#       rename 's/\.orig$//' *.orig
#       rename 'y/A-Z/a-z/ unless /^Make/' *
#       rename '$_ .= ".bad"' *.f
#       rename 'print "$_: "; s/foo/bar/ if <stdin> =~ /^y/i' *

$op = shift;
for (@ARGV) {
$was = $_;
eval $op;
die $@ if $@;
rename($was,$_) unless $was eq $_;


#! /usr/bin/perl
use autodie;
for (@ARGV) {
  rename $_, $_ =~ s/\Q$ENV{ORIGNAME}\E/$ENV{DESTNAME}/r
    and warn "Rename file - [$_]\n";

Or if you're on CentOS, and can't use e.g. cPanel's newer perl:

#! /usr/bin/perl
for (@ARGV) {
  (my $new = $_) =~ s/\Q$ENV{ORIGNAME}\E/$ENV{DESTNAME}/
    and warn "Rename file - [$_]\n";
  rename $_, $new or die "Rename of ``$_'' to ``$new'' failed: $!";

Or if you really need arbitrary Perl:

#! /usr/bin/perl
my $op = shift;
for (@ARGV) {
  my $old = $_;
  eval $op; die $@ if $@;
  next if $old eq $_;
  rename $old, $_ and warn "Rename file - [$old]\n"

Mind the subtle differences.

In the first two cases, adjust your find appropriately:

find /tmp -name "*$ORIGNAME*" -exec /tmp/ {} +

It's not significant that my environment variables are less painful.

By the way, your error was not a Perl one so much as a very obvious find error. find and especially find with -exec is dangerous, yo: have someone who knows what they're doing take a look at your script before you run it.

Why not do the whole thing in Perl?

#! /usr/bin/env perl

use 5.12.0;
use warnings;
use autodie;
use File::Find;
use Getopt::Long;

A little break here...

The File::Find is a standard Perl module that will allow you to do the file find internally inside of Perl. The Getopt::Long is a nice little command that parses the command line arguments for you. Both of these are part of Perl's standard package, and there is absolutely no reason not to use them.

And now, back to our program in progress.

my ($from, $to, $dir);

my $usage =<<USAGE; -from <from> -to <to> -dir <dir>

GetOptions {
    'from=s'     => $from,
    'to=s'       => $to,
    'dir=s'      => $dir,
} or die ($usage\n);

if ( not $from or not $to or not $dir ) {
   die ($usage\n);

Another break... See how nicely Getopt::Long parses the command line? A single function GetOptions does all of the parsing for you. All you need to do is verify the input. (And, GetOptions could even do that for you too!). Take a look at Perldoc and look at the various Modules that are included in almost any installation of Perl. They're just as much as the Perl language as commands such as pop or push, and these modules can make programming in Perl much, much easier.

my @files_found;
find ( sub {
       return unless /$from/;
       @files_found, $File::Find::name;
     }, $dir);

for my $file ( @files_found ) {
   (here be dragons...)
   rename $file, $to_name;

This is a rough outline of your program. It all depends upon what you really want to accomplish, but it does show how you can do everything in a single program rather than relying upon using find, and then your Perl script embedded in a find. All without all that much extra work.

You probably want to add a few more features (like something telling you what each file was renamed to, and maybe include a -dry-run option that you could use to just see what the results would look like without renaming anything.

I prefer to use find to fill in a list of file names that I can operate on later. There's no reason why that couldn't be included in the find. I also like embedding my subroutine directly into my find command. However:

find ( sub {
       return unless /$from/;
       @files_found, $File::Find::name;
     }, $dir);

is equivalent to:

find ( \&wanted, $dir);

sub wanted {
   return unless /$from/;
   @files_found, $File::Find::name;

which might make it easier for you to understand.

To use your program, you'd simply do this:

$ -dir . -from REPLACE_THIS -to with_this


Save the best for last. There's a command called find2perl which will convert your Unix Find command into a Perl script. And, the best part: It's already on your system:

$ find2perl find /tmp -name "*$NAME_THAT_WE_WANT_TO_CHANGE*" -exec /tmp/ \;

#! /usr/bin/perl -w
    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
        if 0; #$running_under_some_shell

use strict;
use File::Find ();

# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

sub wanted;
sub doexec ($@);

use Cwd ();
my $cwd = Cwd::cwd();

# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, 'find', '/tmp');

sub wanted {
    /^.*.*\z/s &&
    doexec(0, '/tmp/');

sub doexec ($@) {
    my $ok = shift;
    my @command = @_; # copy so we don't try to s/// aliases to constants
    for my $word (@command)
        { $word =~ s#{}#$name#g }
    if ($ok) {
        my $old = select(STDOUT);
        $| = 1;
        print "@command";
        return 0 unless <STDIN> =~ /^y/;
    chdir $cwd; #sigh
    system @command;
    chdir $File::Find::dir;
    return !$?;

Since your doexec is just a Perl script, you could replace that whole subroutine with your Perl code.

Need Your Help

C# database connection class not working


Im following a C# database connection tutorial however the code they provide for the connection class has a problem, it has an error on dat_set which I'm assuming needs to be set as a variable but ...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.