100 Languages Speedrun: Episode 11: Tcsh
Tags: tcsh, unix
Published: 2021-12-02 02:27:47

Unix shell was always amazing for interactive use. A lot can be done by just piping a few commands into each other. Then you can put a few commands or pipes into a script file, and it works well enough.

The problem is what happens after that, when you want to add some more complicated functionality to that script. Maybe some command line switches. Maybe some user input. Maybe some error handling. Unix shell turns from amazing to awful really quickly.

These days, nobody except for the Greybeards actually writes nontrivial programs in Unix shell. The only reasonable way is to use a real programming language. Many like Ruby, Python, Perl, and so on work amazingly well within Unix environment.

But before reasonable people stopped writing "shell scripts", there've been attempts to build a "better shell", with both better interactive features, and better support for writing scripts. First Bash and now Zsh pretty much won that race, but for a while there were other contenders, Tsch being one of them. It was even the default shell for early versions on OSX.

Let's take a look!

### Hello, World!

Tcsh is still a Unix shell, so the same `echo` command works like with every other Unix shell:

```
#!/bin/tcsh

echo "Hello, World!"
```

### Loop

As typical with shells, and shell-like languages (like Perl or Tcl), we run into the issue that there's no distinction between string `10` and integer `10`.

Tcsh has two commands for setting variables - `set variable = stuff`  expects string on the right side. `@ variable = stuff` calculates the right side as a number and sets the result of the calculation as the value of the variable:

```
#!/bin/tcsh

set num = 1
while ( $num <= 10 )
  echo $num
  @ num = $num + 1
end
```

There's also some shortcuts like `@ num ++` for this.

As with all shells, `num` means "variable num" (think of it like a container for something), while `$num` mean "value of variable num" (think of it like what that container currently contains).

So `@ num = $num + 1` means. "Take stuff from container `num`, calculate what that `+ 1` is, then store it in container `num`.

In most non-shell-derived languages whatever goes on left of `=` is variable-as-container, and whatever goes on right of `=` is `contents-of-that-container`, so this distinction is based on context, not marked by any special syntax.

`while` syntax is quite C-like. That's

### FizzBuzz

Given all that, FizzBuzz should bo completely unsurprising:

```
#!/bin/tcsh

set num = 1
while ( $num <= 100 )
  if ( $num % 15 == 0 ) then
    echo "FizzBuzz"
  else if ( $num % 3 == 0 ) then
    echo "Fizz"
  else if ( $num % 5 == 0 ) then
    echo "Buzz"
  else
    echo $num
  endif
  @ num ++
end
```

It's arguably slightly cleaner than analogous Bash code:

```
#!/bin/bash

(( num = 1 ))
while (( num <= 100 ))
do
  if (( num % 15 == 0 ))
  then
    echo "FizzBuzz"
  elif (( num % 3 == 0 ))
  then
    echo "Fizz"
  elif (( num % 5 == 0 ))
  then
    echo "Buzz"
  else
    echo $num
  fi
  (( num ++ ))
done
```

Of course in both cases, these are not the only ways to do it.

### Fibonacci

Tcsh doesn't have functions. We have a few things we could do, for example we can call a shell script sort of like a function.

Here's Tcsh version of Fibonacci, with a lot of intermediate variables to make it clearer what's going on:

```
#!/bin/tcsh

set num = $argv[1]
if (( $num  <= 2 )) then
  echo 1
else
  @ a = $num - 1
  @ b = $num - 2
  set c = `./fib.tcsh $a`
  set d = `./fib.tcsh $b`
  @ e = $c + $d
  echo $e
endif
```

So basically we treat the whole shell script like a function - it treats its first command line argument as number, and then prints the answer. Of course this is horrendously inefficient, and it takes 2s to calculate that fib(12) is 144, but it works:

```
./fib.tcsh 12
144
```

### Should you use Tcsh?

As I mentioned so many times before, if you want to write some small program that works well in Unix environment, just use a real programming language. Ruby, Python, and a bit more old school Perl are all fine choices.

For interactive use, Zsh really is the way to go these days. And even if you absolutely insist on writing convoluted shell scripts, Zsh is still a less bad choice than Tcsh.

Unless you have to maintain some old Tcsh code, I can't think of any real reason to use Tcsh these days.

### Code

[All code examples for the series will be in this repository](https://github.com/taw/100-languages-speedrun).

[Code for the Tcsh episode is available here](https://github.com/taw/100-languages-speedrun/tree/master/episode-11-tcsh).