100 Languages Speedrun: Episode 11: Tcsh
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.