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
1 Answer 1
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"
-
1That's what I noticed in the edit four hours ago. This is a very clear answer.RonJohn– RonJohn2025年11月06日 22:35:16 +00:00Commented 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 ... <<EOFsome input line with quoting only for the remote shellEOF. If the input includes any$or backslash you need<<'EOF'or<<\EOFor similar.dave_thompson_085– dave_thompson_0852025年11月07日 01:14:09 +00:00Commented Nov 7 at 1:14 -
2Modern 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.grawity– grawity2025年11月07日 10:55:39 +00:00Commented Nov 7 at 10:55
You must log in to answer this question.
Explore related questions
See similar questions with these tags.
findcare if there are one or multiple files?*logis unquoted and a lot depends on how many matches the shell finds there, as stated in the answer.