1

I have a perl inline replace command in a shell script that isn't working for some reason. With below command, its replacing all ":" with replacement string in the perl command.

When I manually ssh to the box and running the perl command works as expected.

ssh host "cd /x/somedirectory && perl -pi -e 's#\${somehost}:\${someport}#10.20.30.40:8443#g' config/app.properties"

Edit1

Please note that $somehost and $someport are NOT shell variables. I'm looking for a literal text replacement.

What am I doing wrong? I tried using different delimiters, escaping { and } etc but still no luck.

3
  • somehost and someport must not be defined then. Commented Nov 13, 2015 at 16:20
  • @HunterMcMillen I see what you are saying now. $somehost and $someport are not shell variables. I'm looking for a literal text replacement. I'm editing the question Commented Nov 13, 2015 at 16:32
  • 2
    Figuring out escapes in a one-liner inside a shell script is like trying to train ants to juggle. Just do the whole thing in Perl using Net::SSH. Or failing that, put the code from the one-liner inside a file, and run it like ssh host "perl -pi code.pl /x/somedir/config/app.properties Commented Nov 13, 2015 at 18:56

4 Answers 4

3

To create a single-quoted shell literal from a string, escape ' by replacing them with '\''.

To create a double-quoted shell literal from a string, escape \, " and $ by prefixing them with \.


The Perl command you want is

s#\${somehost}:\${someport}#10.20.30.40:8443#g

So the remote shell command you want is

perl -pi -e 's#\${somehost}:\${someport}#10.20.30.40:8443#g' config/app.properties

So the local shell command you want is

ssh host 'perl -pi -e '\''s#\${somehost}:\${someport}#10.20.30.40:8443#g'\'' config/app.properties'

or

ssh host "perl -pi -e 's#\\\${somehost}:\\\${someport}#10.20.30.40:8443#g' config/app.properties"

[Removed cd /x/somedirectory && to keep things simple. Just add it back in.]

Sign up to request clarification or add additional context in comments.

5 Comments

Both versions I posted work. Aside from doing this every day, I have tested them. Did you miscopy something (e.g. used " instead of ')? Or maybe you're not using bash (on both machines) as tagged?
I tried this ssh host "perl -pi -e '\''s#\${somehost}:\${someport}#10.20.30.40:8443#g'\'' /x/web/STAGE2MS034/paymentapiplatformserv/config/app.properties". I get bash: -c: line 0: unexpected EOF while looking for matching ''`
That's doesn't match either of my solutions. You used ", so you need to use the escape mechanism for ", but you used the escape mechanism for '. Either use the appropriate escape mechanism (second solution), or use ' instead of " (first solution).
Ahh..thanks that works. One day I'll get better at bash
Just add each layer of escaping one at a time as i showed. // 'abc'\''def' is 'abc' (abc), \' ('), and 'def' (def) one after the other, resulting in abc'def.
2

The shell on the remote machine will perform another level of escaping. To receive the sequence \$ on the remote machine you have to send the sequence \\\$:

ssh host "cd /x/somedirectory && perl -pi -e 
    's#\\\${somehost}:\\\${someport}#10.20.30.40:8443#g' config/app.properties"

1 Comment

Note: Only works if you remove the line break or if you add \\ before the line break.
2

So, you can write Perl...

#!/usr/bin/perl

use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($host);
my $old = quotemeta("${somehost}:${someport}");
$ssh->system('cd', $some_directory, \\'&&',
             'perl', '-pi', '-e',
             "s|$old|10.20.30.40:8443|g",
             'config/app.properties');

Comments

0

Try this ssh command with here-doc and avoid all escaping:

ssh -t -t host<<'EOF'
cd /x/somedirectory &&
    perl -i -pe 's#\${somehost}:\${someport}#10.20.30.40:8443#g' config/app.properties
exit
EOF

8 Comments

still no luck. You forgot { and } in your answer. I added them but I get same result
@nilesh Are you trying to replace the literal text ${somehost}, or the value of the bash variable $somehost?
@ThisSuitIsBlackNot you got it. I'm trying to replace literal text. $somehost and $someport are not shell variables
@anubhava sorry for the confusion, $somehost and $someport are not shell variables. I'm looking for a literal text replacement
perl -pei 'foo' is equivalent to perl -pe 'i' foo (i.e. run the code i on file foo), you need perl -i -pe 'foo'. Also, you have to escape the $ in the regex so it doesn't mean end-of-line: perl -i -pe 's#\${somehost}:\${someport}#10.20.30.40:8443#g'
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.