Sunday, February 27, 2022

[SOLVED] Shell script when we need to quote or unquote

Issue

I am trying to understand in what situation we should use quote the command while parsing the output from it or when should not.

title="show questions tagged 'bash'" rel="tag">bash

Case 1:

I am using below command into my bash script which works well while using like below which results the correct output.

$ ssh -i /home/apache.ssh/sshKey root@dbhost01 -o StrictHostKeyChecking=no -o PasswordAuthentication=no cat /etc/redhat-release| awk 'END{print $7}'
6.7

Case 2:

While wrapping like "cat /etc/redhat-release| awk 'END{print $7}'" which results the complete file output and skips parsing though.

$ ssh -i /home/apache.ssh/sshKey root@dbhost01 -o StrictHostKeyChecking=no -o PasswordAuthentication=no "cat /etc/redhat-release| awk 'END{print $7}'"
Red Hat Enterprise Linux Server release 6.7 (Santiago)

Please advise what could be the right approach while using this into bash scripts.


Solution

Properly quoting something isn't always just a matter of putting a quote at the beginning, and another at the end; if the string contains characters that'll have special meaning within that type of quotes, you need to escape them or otherwise disable that special meaning.

In this case, it's the $ (in print $7) that's causing trouble. Inside double-quotes, $ initiates parameter, command, etc substitution, so the shell replaces $7 with the value of the seventh argument to the current shell, and there isn't one, so you get ... | awk 'END{print }' being passed to ssh as the command to send to the remote computer. Note that while the $ is also in single-quotes, those are inside the double-quotes and hence get ignored (until they get to the remote shell, that is).

But there's also some confusion about case 1, the one that works. Because the command string is not quoted, and contains |, the local shell parses it into two separate commands in a pipeline:

    ssh -i /home/apache.ssh/sshKey root@dbhost01 -o StrictHostKeyChecking=no -o PasswordAuthentication=no cat /etc/redhat-release
piped into:
    awk 'END{print $7}'

...so the ssh command actually fetches and prints the entire contents of /etc/redhat-release, and then locally that's piped into awk and the seventh field split off and printed.

The moral of the story: commands sent via ssh get parsed (and quotes/escapes applied and removed) twice, once on the local system and a second time on the remote system. It's important to understand what's going to get parsed and applied locally vs what's going to get parsed and applied remotely. There's no simple rule here, you really just need to think about what you want to have happen locally and what you want to have happen on the remote system, and make sure the quoting/escaping you use makes that happen.



Answered By - Gordon Davisson
Answer Checked By - Mary Flores (WPSolving Volunteer)