0

I wrote a script that collects application logs on local machine and then from remote machine.

It has variable oldlogsdate which reads the date of logs I want to collect.

For example, if I enter Apr 23 it works fine because there is only one space, but if I enter Apr 4 (two spaces between Apr and 4) it will remove one space.

Note: This oldlogsdate is also set on remote machine in user's .bash_profile and the entered date is then changed a using sed command.

printf "\n";read -p "Which Date Logs you want to collect = " oldlogsdate
ssh -qt remote-user-name@xxx.xxx.xxx.xxx "sed -i "s/oldlogsdate=.*/oldlogsdate=\'\"$oldlogsdate\"\'/" ~/.bash_profile"

oldlogsdate="Apr 7"

Now why I'm using Apr 23 and Apr 4 it's part of ls command.

Is there a way to retain double spaces in read command, or some other better way?

enter image description here

Kusalananda
  • 333,661
OmiPenguin
  • 4,308

2 Answers2

3

Note your ssh command line, the part with the sed command sent to the other end:

ssh ... "sed -i "s/oldlogsdate=.*/oldlogsdate=\'\"$oldlogsdate\"\'/" ~/.bash_profile"
        ^^^^^^^^^..................................................^^^^^^^^^^^^^^^^^^

You have two quoted strings here, the ones marked with ^. The rest in the middle is not quoted, and that includes the variable expansion $oldlogsdate. Since it's unquoted, it's subject to word splitting, and Apr 7 becomes the two words Apr and 7. See also: When is double-quoting necessary?

Now, ssh is smart enough to glue them back together, but by now the original amount of whitespace is lost, and it just adds a single space.

This is somewhat similar to how the shell forgets the original amount of whitespace in this and echo glues the words together with a single space:

$ echo hello  world
hello world

But note that with SSH, a single level of quotes doesn't help, since SSH passes the command line for the shell on the remote end to interpret, and in that shell too, extra whitespace between words is lost.

So this still doesn't work:

$ ssh localhost echo "hello  world"
hello world

(the local shell removes the quotes, and ssh gets echo and hello world, and passes to the remote echo hello world, which works as above.)

and we actually have to do quoting for both ends to keep the string intact:

$ ssh localhost 'echo "hello  world"'
hello  world

Actually, it would be better to use printf ":%s\n" hello world etc. to show more properly where the words break, but the result is similar.

Switching the quotes so that the double-quotes are the outermost lets the local shell expand the variable, and leaves the single quotes for the remote, which minimizes the amount of expansions it does. You'll still need to backslash-escape any double-quotes you want to send to the other side.

$ greeting="hello  world"
$ ssh localhost "echo '$greeting'"
hello  world

That should work as long as the variable doesn't contain single-quotes itself. If it does, things get uglier, see: Escape a variable for use as content of another script

I think the command line in @sasha's answer looks like it should work for your case.

See also, e.g. this question: Quoting in ssh $host $FOO and ssh $host "sudo su user -c $FOO" type constructs The question at hand there has one more layer of processing, but the answers seem to apply for the "easier" case too.

ilkkachu
  • 138,973
  • Technically, it's not word splitting that happens on the remote shell, it's just normal syntax tokenisation there. word splitting generally refers to the separate process that happens when you leave work expansions ($var, $(cmd), $((arith))) unquoted and involves the $IFS special parameter. – Stéphane Chazelas Apr 27 '21 at 11:47
  • @StéphaneChazelas, yep, rephrased a bit – ilkkachu Apr 27 '21 at 12:05
2

Read command removes double space and Keeps only one

It doesn't. The read command by itself keeps the interior whitespace as is (however it will trim leading and trailing whitespace unless you set IFS to empty; it also will mangle backslashes if you don't use -r).

read myVar <<<'Apr  4'
echo "$myVar"  # will output: Apr  4

That's you who then lose spaces due to not double-quoting the variables:

myVar2='Apr  4'
echo $myVar2  # will mangle spaces, please always use "$myVar2" instead

Not quoting the variables properly not only makes the script misbehave but also may introduce potential security risks.

A bit more correct command would be

ssh -qt remote-user-name@xxx.xxx.xxx.xxx "sed -i 's/oldlogsdate=.*/oldlogsdate=\"$oldlogsdate\"/' ~/.bash_profile"

But it's not versatile and not safe anyway, because it doesn't take into account that the $oldlogsdate value can potentially contain not only spaces but also apostrophes, slashes, backslashes, dollar signs and exclamation marks.

sasha
  • 129