6

In my C-shell script (tcsh specifically) I have been trying to declare an array with six values: x, nx, y, ny, z, nz. After some trial and error I discovered three different ways of declaring the array I want:

set arrname = ("x" "nx" "y" "ny" "z" "nz")
set arrname = (x,nx,y,ny,z,nz)
set arrname = {x,nx,y,ny,z,nz}

but the following line doesn't work:

set arrname = {"x" "nx" "y" "ny" "z" "nz"}

The above line produces the following error:

Missing }.

My question is what is different between () and {} that makes the fourth declaration I've listed not work?

  • Note: I have also discovered that if I use both quotation marks AND commas together, both () and {} work. – NeutronStar Jun 27 '13 at 20:37
  • faqs.org/faqs/unix-faq/shell/csh-whynot – Barmar Jun 27 '13 at 20:39
  • 2
    Your second example gives $arrname a single element with the value x,nx,y,ny,z,nz. I'm a bit surprised the version with { braces } works. – Keith Thompson Jun 27 '13 at 20:40
  • 1
    and you can the echo ${arrname[2]} (for example)? Good luck to all – shellter Jun 27 '13 at 20:40
6

{} are shell expansion, Brace expansion is a mechanism by which arbitrary strings may be generated. Patterns to be brace-expanded take the form of an optional PREAMBLE, followed by a series of comma-separated strings between a pair of braces, followed by an optional POSTSCRIPT. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right. detail link

so, if you put comma then you will not get missing } error:

   set arrname = {"x","nx","y","ny","z","nz"}
  • 1
    So the interesting thing that's being demonstrated here is that while array assignments normally require parentheses, you can omit the parentheses when the values are generated by a brace expansion. set foo=x{a,b,c,d,e}y has the same effect as set foo=(x{a,b,c,d,e}y) – Wumpus Q. Wumbley Jun 27 '13 at 23:48
5

This:

set arrname = ("x" "nx" "y" "ny" "z" "nz")

is an ordinary array assignment (BTW, the quotation marks are not needed in this case).

This:

set arrname = (x,nx,y,ny,z,nz)

also makes $arrname an array, but it has only one element, with the value x,nx,y,ny,z,nz (the commas are not special in this context).

This:

set arrname = {x,nx,y,ny,z,nz}

uses a glob pattern; just as {foo,bar}.txt expands to foo.txt bar.txt, so {x,nx,y,ny,z,nz} expands to x nx y ny z nz.

Apparently tcsh allows you to use {x,nx,y,ny,z,nz} as an array initialization, though if you expand it yourself to:

set arrname = x nx y ny z nz

it sets $arrname to just x and silently ignores the other arguments. This is one of many odd glitches in the way csh and tcsh parse command arguments. I've used csh and tcsh for decades myself (though I've recently switched mostly to bash), and I routinely run into cases like this where I have to experiment to determine how something is going to work.

If you want to set $arrname to an array value, use parentheses, and don't use commas.

And as barmar mentioned in a comment, you should read this:

http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/

csh and tcsh do have somewhat more convenient array syntax than bash has. In csh and tcsh, you can refer to the 3rd element of an array as $arrname[3]; in bash you have to add braces: ${arrname[3]}. Also, bash arrays are 0-based, while csh/tcsh arrays are 1-based. But the greater consistency of bash's syntax and semantics, IMHO, more than makes up for this.

Some simple array examples, in csh:

% set arr = ( 10 20 30 )
% echo $arr
10 20 30
% echo $arr[3]
30

and in bash:

$ arr=(10 20 30)
$ echo ${arr[@]}
10 20 30
$ echo ${arr[*]}
10 20 30
$ echo ${arr[2]}
30

(The [@] and [*] syntax behave subtly differently; see the bash documentation for details.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.