7

I’m having trouble doing something basic with csh. I have a string:

set newCmd = "$expansionCmd –option1 –option2 …"

And I’m creating an array of these strings, which I later want to execute:

set expansionCmdList = ($expansionCmdList[*] "$newCmd")   
#I also tried without quotes, e.g. just $newCmd

Finally I try to iterate over and execute these commands:

foreach exCmd ($expansionCmdList) 
    `exCmd`    #execute it in the shell
end 

However the problem is that the array entries are not the full string, but every part of the string separated by whitespace, i.e. the first entry is just “$expansionCmd”, the next entry would be “—option1” etc.

Apologies in advance for using c shell, my company's code base is stuck with it.

2 Answers 2

11

Any time you are expanding an entire array and want to keep its individual elements' identities intact, you need the :q (for "quoted") modifier on the expansion. Otherwise, as soon as you do something like set expansionCmdList=($expansionCmdList[*] "$newCmd"), all previous commands in the list are split out into their component words, each of which is now its own array element. Simple demonstration:

% set a = ( a "b c" d )
% echo $a[2]
b c
% set a = ( $a[*] e )
% echo $a[2]
b

Oops, you've messed up the array before you even get to your execution loop. Things go much better with :q:

% set a = ( a "b c" d )
% set a = ( $a:q e )
% echo $a[2]
b c

You need to use the same modifier in the for loop:

foreach exCmd ($expansionCmdList:q) 

Finally, `exCmd` tries to run a command literally named "exCmd", and then take its output and run that as a command. What you probably want to do is simply execute a command equal to the value of the variable. You will likely run into more whitespace woes here, and you can't solve them by making each command an array since csh doesn't support arrays of arrays. Fair warning. But if the commands don't have any quotation needs, this will work:

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

4 Comments

thanks man... I swear the only documentation I can find on c shell is people saying not to use c shell.
Well, the only significant remaining reason not to use csh for scripting is that csh is not a very good scripting language... due to things like the fact that you have to twist aliases into knots in order to have any sort of subprogram capability. But if that's what you have, that's what you have. And it did have arrays and built-in arithmetic long before the POSIX shells did. :)
Note that using ${array}:q will not work -- it must be $arr:q.
@SeanAllred of course. ${array}:q is specifically using the curlies to prevent the application of the modifier and get a literal :q in the result. If you want to use curlies and still apply the modifier, it's ${array:q}.
1

Mark's solution is clearly superior for most applications, but there is another option. Instead of using foreach directly, get the size of the array and iterate through the sequence:

set BUILD_MATRIX = ( "makefile.make:make --jobs --makefile=makefile.make" \
                     "Makefile:make --jobs --makefile=Makefile" \
                     "build.xml:ant" )

foreach i ( `seq ${#BUILD_MATRIX}` )
  echo $i
  echo $BUILD_MATRIX[$i]
end

(copied from Accessing array elements with spaces in TCSH)

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.