0

I need to get the local time and hostname of the remove server.

Following command executes correctly on local server.

echo "{\"hostname\":\"`hostname`\" , \"date\":\"`date '+%Y-%m-%d %H:%M:%S'`\"}"

and return the following output correctly:

{"hostname":"server1" , "date":"2018-10-29 17:43:51"}

But when I execute the same command on a remote server, it fails:

var1=`ssh server2 " echo "{\"hostname\":\"`hostname`\" , \"date\":\"`date '+%Y-%m-%d %H:%M:%S'`\"}" "`

bash: ": command not found

bash: +%Y-%m-%d %H:%M:%S: command not found

`ssh server2 " echo "{\"hostname\":\"`hostname`\" , \"date\":\"`date '+%Y-%m-%d %H:%M:%S'`\"}" "`

bash: ": command not found

bash: "} : command not found

bash: {hostname:hostnamedate: command not found

1
  • 2
    Always use $( ... ) in place of backticks. Backticks change how backslashes and quotes within them are parsed, so you need to modify your code every time you add a new nesting layer on the outside. Commented Oct 29, 2018 at 22:23

3 Answers 3

1

Try:

var1=$(ssh server2 " echo "{\"hostname\":\"\$\(hostname\)\" , \"date\":\"\$\(date '+%Y-%m-%d %H:%M:%S'\)\"}" ")

Basically, you cannot nest `` backticks so you have to use $() and the commands that you want to execute remote (hostname and date) have to be escaped.

Sign up to request clarification or add additional context in comments.

1 Comment

it's possible to nest backticks, just painful -- involves a whole lot of backslashes.
1

Charles' answer is the best for JSON. In case you don't have jq, you could do this:

var1=$(ssh server2 bash -s << 'EOF'
  h=$(hostname)
  d=$(date)
  printf '{"hostname": "%s", "date": "%s" }\n' "$h" "$d"
EOF
)

1 Comment

nod -- I used the OP's quoting because they did, not because it was good quoting.
1

Using bash -s with a quoted heredoc can be used to run your code exactly as it is, without any changes:

ssh server2 bash -s <<'EOF'
echo "{\"hostname\":\"`hostname`\" , \"date\":\"`date '+%Y-%m-%d %H:%M:%S'`\"}"
EOF

That said, in general, using string concatenation to generate JSON is a bad idea (can lead to output that isn't actually valid JSON if your commands return unexpected output). Consider newline-delimiting your content as it passes over SSH, and then generating JSON locally with a syntax-aware tool such as jq:

IFS=$'\n' read -r -d '' hostname date < <(
  ssh server2 'hostname && date +"%Y-%m-%d %H:%M:%S" && printf "\0"'
)
jq --arg hostname "$hostname" --arg date "$date" \
  '{ "hostname": $hostname, "date": $date }'

2 Comments

@codeforester, using IFS=$'\n' lets us use -d '' to read multiple values and get a true-or-false result letting us know if we successfully read them both (and if they both ran on the remote machine, since only if that happened will the stream be terminated by a NUL). Thus, we could put a || { echo "Unable to collect remote hostname"; exit 1; } or such on the read, which wouldn't work properly otherwise.
Similarly, as much as I detest set -e, the practice above would make it trigger in the event of a failure from ssh.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.