Backticks interpolate backslash escapes just like double quotes (the only exception being qx'...' ), while single quotes do not (Quote and Quote like Operators).
`$_vim_cmd . ' -c "normal \r" -c wq ~/vimwiki/testing.md'`;
What's being passed to the external command* is a literal carriage return byte (despite all the extra quotes around it - Perl doesn't care about quotes within quotes).
my $value = ' -c "normal \r" -c wq ~/vimwiki/testing.md'; `$_vim_cmd $value`;
Here, you're setting up a Perl string to contain the two-byte string \ plus r, and passing that to backticks, so that two-byte string then becomes part of the argument list*.
(* Update: To clarify, what I mean is that this is Perl's interpretation of the string - what the external command actually receives in its argv after the string is optionally passed through the shell is a different matter, as the following explains.)
use warnings;
use strict;
use Data::Dump;
my $perl = "$^X -wMstrict -MData::Dump -e 'dd\\\@ARGV' -- ";
dd qq{'"normal \r"'}; # prints "'\"normal \r\"'"
print `$perl '"normal \r"'`; # => @ARGV is ("\"normal \r\"")
my $value = '"normal \r"';
dd qq{$value}; # prints "\"normal \\r\""
print `$perl $value`; # => @ARGV is ("normal \\r")
# "strace -s256 -fe trace=execve" (abbreviated by me) shows:
# execve("/bin/sh", ["sh", "-c", "perl ... -- '\"normal \r\"'"], ...
# execve("/bin/sh", ["sh", "-c", "perl ... -- \"normal \\r\""], ...
Since you don't say what your desired result is, it's unclear to me what you mean by "works" and "doesn't work", but IMO this is another great reason to avoid the shell - as you can see above, Perl is calling the shell, and since it's unclear what this "default shell" is, this code is not going to be portable. It'd be better if you use something like capturex from IPC::System::Simple and then use Perl's normal quoting mechanisms to set up the exact strings that you want to get passed to the external process.
use IPC::System::Simple qw/capturex/;
print capturex($^X, qw/ -wMstrict -MData::Dump -e dd@ARGV -- /,
"\r", "\\r");
# => prints ("\r", "\\r")
Plus, all the other advice from my node here applies as well, e.g. you should check $? for errors. Also, using backticks in void context doesn't make much sense, maybe you want system instead? That supports avoiding the shell without having to pull in an extra module. |