I need to create a script that should get the newest file based on a filename pattern from server A on server B.
The command I run on server B is like this (server A is 103.11.34.111):
ssh user@103.11.34.111 'find /data/path -name "CDR*$file_date" -printf "%TY-%Tm-%Td %TH:%TM:%.2TS\n" | sort -rn | head -1'
$file_date
is a variable that defines a date with format YYYYMMDD
I get error as below when I run ./myscript.sh
*** buffer overflow detected ***: ssh terminated
I suspect there is issue in my command because if I run the command with
ssh user@103.11.34.111 'find /data/path -name "CDR*$file_date" | sort -rn | head -1'
or
ssh user@103.11.34.111 'find /data/path -printf "%TY-%Tm-%Td %TH:%TM:%.2TS\n" | sort -rn | head -1'
it manages to get the result, however if I run with full parameters there is the buffer overflow.
The value of $file_date
is not visible on the remote server because you are using single quotes. The crucial change to fix that is to use double quotes. You have to switch to single quotes internally (or otherwise escape or quote the other quotes).
ssh user@103.11.34.111 "find /data/path -name 'CDR*$file_date' -printf '%TY-%Tm-%Td %TH:%TM:%.2TS\n' | sort -rn | head -1"
See also Difference between single and double quotes in Bash
The pipe to sort | head
is rather memory-intensive; keeping all the lines in memory so that they can be sorted is superfluous when all you need is the overall maximum value. So the following should be both more efficient in terms of memory and run faster.
ssh user@103.11.34.111 "find /data/path -name 'CDR*$file_date' -printf '"%TY-%Tm-%Td %TH:%TM:%.2TS\n"' |
awk '\$0 > n { n = $0 } END { print n }'"
Notice how the dollar sign in the Awk script needs to be backslash-escaped because the double quotes will cause anything with an unescaped dollar sign to be evaluated as a variable by the local shell before ssh
runs.
If you don't expect a lot of output, you could run the sort
and head
locally, in which case no quoting is required around the pipeline.
ssh user@103.11.34.111 find /data/path -name "CDR*$file_date" -printf "'%TY-%Tm-%Td %TH:%TM:%.2TS\n'" |
sort -rn | head -1
... but as I expect the find
command to potentially produce a nontrivial amount of output, I have assumed you want to run the entire pipeline remotely, and only send the final result back over the ssh
connection.
I'll emphasize again that this only runs ssh find
and then pipes the output back to your local shell, which runs the pipeline through sort
and head
locally.
(And even then, the Awk script from above is probably an improvement over keeping all the lines you receive in memory at the same time so you can sort them.)
Notice also how the argument to -printf
needs to be doubly quoted (as in, both double and single quoted; or you could backslash-escape the space) to keep it as a single string from both the local and the remote shell.