3

So, I wrote a simple script to convert sh-style export key=value statements to csh-style setenv key value for docker-machine env.

#!/bin/sh
docker-machine env | sed -e 's/export/setenv/' -e 's/=/ /' -e '$d'
echo '# eval `docker-machine env`'

and it produces the following output

setenv DOCKER_TLS_VERIFY "1"
setenv DOCKER_HOST "tcp://<ipv4 address>:<port>"
setenv DOCKER_CERT_PATH "<HOME>/.docker/machine/machines/default"
setenv DOCKER_MACHINE_NAME "default"
# Run this command to configure your shell:
# eval `docker-machine env`

In my .tcshrc I've bound this script to the alias docker-machine-env-csh.

I can source the output of this script using a temporary variable just fine

% docker-machine-env-csh >! /tmp/csh && source /tmp/csh

However, I don't seem to be able to directly eval the result of this alias

% eval `docker-machine-env-csh`
setenv: Too many arguments.

Or assign it to a variable in a way that preserves newlines.

% set a = `docker-machine-env-csh`
% printf "%s\n" "$a"
setenv ... setenv ... setenv ...

Although, weirdly printf "%s\n" `docker-machine-env-csh` seems to insert a newline between every token.

% printf "%s\n" `docker-machine-env-csh`
setenv
...
...
setenv
...
...

How do I preserve newlines in tcsh command substitution?

1

1 Answer 1

9

There are plenty of good reasons why it's recommended not to use csh or tcsh for scripting. That's one of those.

To get the output of some command verbatim into a shell variable in tcsh, you need something like:

set temp = "`(some command; echo .) | paste -d . - /dev/null`"
set var = ""
set nl = '\
'
foreach i ($temp:q)
  set var = $var:q$i:r:q$nl:q
end
set var = $var:r:q

Don't forget to use $var:q syntax to expand the variable as in:

printf '<%s>\n' $var:q

The POSIX sh equivalent would be:

var=$(some command; echo .)
var=${var%.}

Now, if your docker-machine-env-csh command did output the information on one line only, or at least with each line terminated with a ; and without comments so that when joined with spaces they still are valid csh code (like applications such as dircolors or ssh-agent do when they want their output to be passed to csh's eval), then you could do:

set var = "`docker-machine-env-csh`"
printf '%s\n' "$var"
# or printf '%s\n' $var:q
# or printf '%s\n' "$var:q"

With set var = `docker-machine-env-csh`, tcsh splits on blanks (and creates an array variable), while with set var = "`docker-machine-env-csh`", it splits on newline only (still an array variable, but if the output has only one line, that array has only one element).

Here you can use "$var" in place of $var:q because $var doesn't contain newline characters. "$var" would join the array elements with space while $var:q would preserve them (here there's only one element, so it makes no difference). If those array elements may contain newlines and you wanted to join them with space, you'd use "$var:q".

So maybe you can modify your script like:

#! /bin/sh -
docker-machine env | sed '
  s/export/setenv/
  s/=/ /
  /^#/!s/$/;/
  $d'
echo '# eval "`docker-machine env`"'

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.