问题描述:

The following

echo text | perl -lnE 'say "word: $_\t$_"'

prints

word: text text

I need

word: 'text' 'text'

Tried:

echo text | perl -lnE 'say "word: \'$_\' \'$_\'";' #didn't works

echo text | perl -lnE 'say "word: '$_' '$_'";' #neither

How to correctly escape the single quotes for bash?

Edit:

want prepare a shell script with a couple of mv lines (for checking, before really renames the files), e.g tried to solve the following:

find . type f -print | \

perl \

-MText::Unaccent::PurePerl=unac_string \

-MUnicode::Normalize=NFC -CASD \

-lanE 'BEGIN{$q=chr(39)}$o=$_;$_=unac_string(NFC($_));s/[{}()\[\]\s\|]+/_/g;say "mv $q$o$q $_"' >do_rename

e.g. from the filenames like:

Somé filénamé ČŽ (1980) |Full |Movie| Streaming [360p] some.mp4

want get the following output in the file do_rename

mv 'Somé filénamé ČŽ (1980) |Full |Movie| Streaming [360p] some.mp4' Some_filename_CZ_1980_Full_Movie_Streaming_360p_some.mp4

and after the manual inspection want run:

bash do_rename

for running the actual rename...

网友答案:

You can use ASCII code 39 for ' to avoid escape hell,

echo text | perl -lnE 'BEGIN{ $q=chr(39) } say "word: $q$_$q\t$q$_$q"'
网友答案:

You can use:

echo text | perl -lnE "say \"word: '\$_'\t'\$_'\""
word: 'text'    'text'

BASH allows you to include escaped double quote inside a double quote but same doesn't apply for single quoted. However while doing so we need to escape $ to avoid escaping from BASH.

网友答案:

OK, based on the statement of the problem you're having. My suggestion would be - don't pipe find to perl, that's just asking for all kinds of annoyance.

I'm not entirely familiar with the modules, but would suggest you try something like this:

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;
use Text::Unaccent::PurePerl qw ( unac_string ); 
use Unicode::Normalize qw ( NFC );
use Getopt::Std;
use File::Copy qw ( move );
use Encode qw(decode_utf8);

my %opts;
#x to execute, p to specify a path. 
#p mandatory. 
getopts('xp:',\%opts);


#this sub is called for each file, by the find function.
#$File::Find::name is the full path to the file.
#$_ is just the filename.     
sub rename_unicode_files {
   #skip if it's not a file. 
   next unless -f $File::Find::name;
   #convert name with functions from your example. 
   my $newname = unac_string(NFC(decode_utf8($File::Find::name)));
   $newname =~ s/[{}()\[\]\s\|]+/_/g;

   #could apply other transforms here, such as regular expressions. 

   #if the two names are different, consider moving. 
   unless ( $newname eq $File::Find::Name ) {
       print "Would rename: $File::Find::Name to $newname\n";

       #actually do it, if '-x' is specified. 
       if ( $opts{x} ) { move ( $File::Find::name, $newname ); };
   }
}

#require -p <pathname> or otherwise print how to use. 
unless ( -d $opts{p} ) { 
   print "Usage: $0 -p <pathname> [-x]\n";
   exit;
}

#trigger find with callback to subroutine, over the '-p <path>'. 
find ( \&rename_unicode_files, $opts{p} );

Extend with something like GetOpt::Std to check if you've specified an option - so you run normally, you get 'this is what I would do' and if you specify a particular flag, it actually does it.

And either use the perl builtin rename or the one available from File::Copy

This will neatly avoid a lot of the escaping and interpolating problems you're having, and I think leave you with generally more readable and useful code.

Edit: Given a comment suggesting that the above is 'too long' how about:

#!/usr/bin/perl
use File::Find; use Text::Unaccent::PurePerl qw ( unac_string ); use Unicode::Normalize qw ( NFC ); find( sub { next unless -f $name; print "mv \'$File::Find::Name\' \'",unac_string( NFC($File::Find::name) )."\'\n"; }, "." );

Still not convinced of the values of the approach. Even if it is only run occasionally - that's even more reason to make it as clear as possible.

相关阅读:
Top