3

I wrote a script that needs to call a command and pass on arguments. My script has its own parameters but some need to be passed through. This fails when arguments to my script have spaces in them.

Here is the script, reduced to the passing on of arguments:

#!/bin/tcsh

set passthrough = ""

checkparams:
if ( $# > 0 ) then
  # Add the argument to passthrough, ensuring spaces are preserved
  set passthrough = "$passthrough '${1:q}'"

  # Show what has been added in one go
  echo "Added passthrough: '${1:q}'"

  shift
  goto checkparams
endif

# Using echo here instead of the real command
echo $passthrough

Calling this script shows the problem:

user@host:/home/user/bin
-> ./test_preserve_passthrough a "b    b" c
Added passthrough: 'a'
Added passthrough: 'b    b'
Added passthrough: 'c'
'a' 'b b' 'c'

As you can see, the 4 spaces between the 'b's disappear. In fact, when I pass a single argument with spaces in it, echo receives not one argument but many as the single string will be broken up by its spaces " ". I tried many ways of quoting (single, double, {$x:q}) and combinations but still cannot preserve the spaces in any way.

When an argument is given to my script like a (TAB-completed) filename this\ \ is\ a\ file\ with\ spaces\ in\ its\ name the backslashes need to be removed, and in the above example with a "b b" c three arguments need to be passed on unchanged: a and b b and c.

1 Answer 1

5

Use an array. csh was the first shell with support for arrays from the late 70s. There are many things csh/tcsh got horribly wrong, including quoting, to the point that most people (me included) would highly recommend not to use it, but at least its array design is not as bad as in ksh/bash.

Here:

#!/bin/tcsh -f

set passthrough = ()

checkparams:
if ( $# > 0 ) then
  # Add the argument to passthrough, ensuring spaces are preserved
  set passthrough = ( $passthrough:gQ $1:Q )

  # Show what has been added in one go
  printf "Added passthrough: '%s'\n" $1:Q

  shift
  goto checkparams
endif

# Using printf here instead of the real command
echo "$#passthrough elements:"
printf '<%s>\n' $passthrough:gQ

You need 6.23.00 or newer for :Q (needed to preserve empty elements).

Here however, the whole script could be written just:

set passthrough = ( $argv:gQ )

As you end up copying the whole of $argv into $passthrough.

If you have to loop over the positional parameters, using a foreach loop would be more conventional than that goto-based approach.

set passthrough = ()
foreach arg ( $argv:gQ )
  set passthrough = ( $passthrough:gQ $arg:Q )
end
2
  • Thanks very much, this does look like a path to a solution. In practice it still does not quite work for me: Those arguments intentionally separated by spaces will now be joined to one argument. Also, If I call the script from the commandline and a filename like this\ \ is\ a\ file\ with\ spaces is given the backslashes are preserved and the file cannot be found by the child process. Can we quote a little less perhaps? Editing the Question to make the request more precise...
    – Ned64
    Commented May 20 at 10:21
  • Tested and it might be ${passthrough[*]:gQ} when calling? I do not understand it enough to be sure....
    – Ned64
    Commented May 20 at 10:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .