3

All three servers are RHEL8.

When run locally, these commands run as expected:

Node_A:

$ find /var/log/postgresql -name '*log' -type f -size +4096c
/var/log/postgresql/postgresql-2025年11月06日_11.log
/var/log/postgresql/postgresql-2025年11月06日_10.log

Node_B:

$ find /var/log/postgresql -name '*log' -type f -size +4096c
/var/log/postgresql/postgresql-2025年11月05日_20.log

But when run remotely as ssh parameters, one fails, but the other works as expected.

$ ssh FISPCDSPGS401A find /var/log/postgresql -name '*log' -type f -size +4096c
find: paths must precede expression: CNDT-INC2829798B.log
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

(CNDT-INC2829798B.log is a file in FISPCDSPGS401A's $HOME for the user I'm logging in as.)

$ ssh FISPCDSPGS401B find /var/log/postgresql -name '*log' -type f -size +4096c
/var/log/postgresql/postgresql-2025年11月05日_20.log

Why would that be?

EDIT: when running ssh -v, I see that the single-quotes get eaten:

debug1: Sending command: find /var/log/postgresql -name *log -type f -size +4096c
asked Nov 6 at 16:46
6
  • 1
    You should quote in the context of the local shell and separately in the context of the remote shell. See this answer. Commented Nov 6 at 16:50
  • @KamilMaciorowski then it should fail both times. One succeeds, though, and the other fails. Commented Nov 6 at 16:54
  • 2
    Because on one machine, it expands to a file name, while on the other, it expands to two file names, where find only expects one. Commented Nov 6 at 16:57
  • @choroba why should find care if there are one or multiple files? Commented Nov 6 at 16:59
  • 1
    @RonJohn See this other answer. On the remote side your *log is unquoted and a lot depends on how many matches the shell finds there, as stated in the answer. Commented Nov 6 at 17:00

1 Answer 1

16

This is all about quoting (or the lack of it).

Consider locally,

find /var/log/postgresql -name '*log' -type f -size +4096c

the quotes around *log are handled by the shell and tell it that the content is to be treated literally. So the shell passes these four characters to find. Specifically, it does not pass the quotes themselves as it's already used those to interpret the string as a literal.

Now consider your remote invocation,

ssh FISPCDSPGS401B find /var/log/postgresql -name '*log' -type f -size +4096c

The local shell handles the quotes round *log exactly as before and this time passes the four character value to ssh. This in turn passes its resulting command line to the remote server FISPCDSPGS401B:

find /var/log/postgresql -name *log -type f -size +4096c

Notice that there are no quotes around *log because the local shell has already processed them. The *log either matches zero, one, or more files in the remote user's home directory. If it's zero you win and the two words -name *log are passed literally to find. If it's one match, for example to a file called analog, you get -name analog passed to find. If you get multiple matches find will crash and burn, trying to parse something like -name analog anotherlog nomoreplease.log -type f .... This last case is the cause of the error you're showing in your question.

The solution is to provide outer quotes to the original ssh command so that the inner quotes around *log are not processed by the local shell but instead are included in the string passed to the remote host:

ssh FISPCDSPGS401B "find /var/log/postgresql -name '*log' -type f -size +4096c"
answered Nov 6 at 19:38
3
  • 1
    That's what I noticed in the edit four hours ago. This is a very clear answer. Commented Nov 6 at 22:35
  • In this case the multi-quoting isn't bad, but in cases where it is (awk and perl are common offenders) you can send the commandline as input (to the remote shell) instead of arguments (to the local ssh, passed to the remote shell): ssh ... <<EOF some input line with quoting only for the remote shell EOF. If the input includes any $ or backslash you need <<'EOF' or <<\EOF or similar. Commented Nov 7 at 1:14
  • 2
    Modern Bash has a way to automate the nested quoting: args=(find /var/log -name "*log" -type f); ssh $host "${args[*]@Q}" will produce a string that has each array item separately quoted. Commented Nov 7 at 10:55

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.