2

Let's examine my problem in layers:

sleep 3; echo hello

sleeps for three seconds and echoes "hello"

ssh localhost "sleep3; echo hello"

does the same on a remote host over ssh

var=$(ssh localhost "sleep3; echo hello")

does the same but stores "hello" in var

(time var=$(ssh localhost "sleep3; echo hello")) 2>&1

does the same and times it, but since time outputs to stderr, I redirected stderr to stdout, so that I can do this

timer=$((time var=$(ssh localhost "sleep3; echo hello")) 2>&1)

which should make the remote machine wait for 3 seconds, echo "hello" which should be stored on a local machine's variable var, and time the entire process after which the timed value is stored in variable timer.

But unfortunately, var is EMPTY (it works fine in example #3)! For the purpose of my code, it is necessary to store output of ssh in one variable, and ssh execution time in the other, without the use of "more advanced" commands as /bin/time, date, etc... I am sure there is a clever (i.e. shell-only) way of doing this, but I'm not clever enough to figure it out by my self. Any help is greatly appreciated.

Here's a thread that might be useful: [How to store standard error in a variable in a Bash script

2
  • Parentheses create a subshell. Variables assigned in the subshell are not visible in the parent shell. Commented May 31, 2014 at 13:57
  • how should I export or . it then? Commented May 31, 2014 at 13:59

2 Answers 2

2

Commands run within parentheses, or when doing command substitution, are run in a subshell. Variables in the subshell don't persist after the subshell completes. The simplest solution is to use a file:

timer=$(time ssh localhost "sleep 3; echo hello" 2>&1 >/tmp/var)
var=$(</tmp/var)
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you. but I already thought about that. The problem is -my command runs in a loop, and there is going to be a loooot of writing, so would avoid that, if possible...
Sorry, but I can't think of any way to set two variables in the same statement. Command substitution has to run in a subshell, because its output is redirected to a pipe .
Not every write to a file goes immediately to disk; small frequent writes that don't overflow the write cache will be treated as a single transaction to disk. Further, it's possible that your /tmp is configured as an in-memory file system, which means you would be just writing to a large, shared variable that masquerades as a file.
It turns out that /tmp MUST BE configured as ramfs, because problems occur when there are multiple simultaneous connections to the server.
For simultaneous connections, use this: filename="/tmp/var_$RANDOM" and replace every /tmp/var with "$filename"
0

Barmar's answer is good, but it's missing parentheses (timer leaks to stdout). The correct answer would be:

time=$((time ssh localhost "sleep 3; echo hello" &>/tmp/key) 2>&1); key=$(</tmp/key)

which makes the remote machine wait for 3 seconds, echo "hello" which is stored in the local machine's variable var, and time the entire process after which the timed value is stored in variable timer, while doing all that in complete silence.

Comments

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.