0

I am trying to check whether a certain package is installed on remote machine in bash script.

If I execute the following statement on the machine itself the result is 1 (installed) in file check.txt, which is correct:

dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed" > /home/someuser/check.txt

However, if I execute the same command in SSH session, the result is always 0.

Can somebody explain why and how to correct this?

Thank you.

#!/bin/bash
ADDRESS=SOMEUSER@$SOMESERVER

function run {
    ssh $ADDRESS /bin/bash $@
}

run << SSHCONNECTION

dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed" > /home/someuser/check.txt

SSHCONNECTION

1 Answer 1

3

Change your script: either run << \SSHCONNECTION or dpkg-query -W -f='\${Status}' nano.  Currently, your local shell is trying to expand ${Status} (yes, even though it’s in single quotes) because it’s in a here document.  (And it’s presumably expanding to a null string.) 

The first part is fairly well documented.  The POSIX Shell Command Language specification, Section 2.7.4 Here-Document says:

The format is … [n]<<word
      ︙
If any part of word is quoted… the here-document lines shall not be expanded.
      ︙
If no part of word is quoted, all lines of the here-document shall be expanded …

bash(1) says essentially the same thing.

The second part is not so clearly documented.  The above sentence from the POSIX specification continues:

If no part of word is quoted, all lines of the here-document shall be expanded for parameter expansion, command substitution, and arithmetic expansion.  In this case, the <backslash> in the input behaves as the <backslash> inside double-quotes (see Double-Quotes).

That section also says,

The here-document shall be treated as a single word that begins after the next <newline> and continues until there is a line containing only the delimiter and a <newline>, …

By contrast, Section 2.3 Token Recognition says:

When an io_here token (i.e., a << or <<-) has been recognized by the grammar (see Shell Grammar), one or more of the subsequent lines immediately following the next NEWLINE token form the body of one or more here-documents and shall be parsed according to the rules of Here-Document.

When it is not processing an io_here, the shell shall break its input into tokens by applying the first applicable rule below …

and then lists ten rules, including

  1. If the current character is <backslash>, single-quote, or double-quote and it is not quoted, it shall affect quoting for subsequent characters up to the end of the quoted text.

So I guess we need to read between the lines to see that text in here-documents is treated almost as if it is already in double quotes, and it is processed only for parameter expansion, command substitution, and arithmetic expansion (and limited backslash processing), and not for quote removal.


Also, you should always quote your shell variable references (e.g., "$ADDRESS" and "$@") unless you have a good reason not to, and you’re sure you know what you’re doing.

1
  • I'm quite new to Bash and really appreciate your detailed explanation. Thank you.
    – Alex
    Nov 23, 2016 at 1:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .