4

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...

kobame
  • 5,766
  • 3
  • 31
  • 62
  • What problem are you actually trying to solve? e.g Why do you need to have single quotes around text? – Hunter McMillen Feb 18 '15 at 18:57
  • 1
    And the moral of this story is - using daisy chains of scripting language is asking for pain, when using one or other is a perfectly valid and acceptable solution to the problem. – Sobrique Feb 18 '15 at 19:03
  • http://stackoverflow.com/questions/20955609/why-is-the-same-as-argv-in-a-perl-one-liner – hmatt1 Feb 18 '15 at 19:12
  • @Sobrique - edited the question - for the real problem what I'm solving. Could you please be more verbose about the _moral of this story_? – kobame Feb 18 '15 at 19:40
  • `use File::Find;` and do it all in Perl. – Sobrique Feb 18 '15 at 21:08

4 Answers4

4

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"'
mpapec
  • 50,217
  • 8
  • 67
  • 127
3

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.

anubhava
  • 761,203
  • 64
  • 569
  • 643
2

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.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • 1
    Small corrections: You need to add: `use Encode qw(decode_utf8);` and change to `my $newname = unac_string(NFC(decode_utf8($File::Find::name)));`, the `GetOpt::Std` is `Getopt::Std` – kobame Feb 18 '15 at 22:41
0

There is a trivial solution using zsh shell and SQL-like (at least PostgreSQL and Oracle) quoting style:

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

To quote a ' you simply double it and use '' in this mode.

Tomasz Pala
  • 111
  • 4