# 前言
相信在IC行业中不少公司使用cshell作为脚本语言之一,很不幸的是目前网络上cshell的中文介绍少之又少,绝大部分是bash的介绍。近期有幸阅读了一本cshell cookbook,想和志同道合的朋友一起探讨一下,故发布于此。
下面我将从cshell的变量,字符处理,文件处理和基本的语句结构进行介绍。在这之前我假设读者已经了解一些cshell的基本知识,至少了解如何跑cshell的脚本,即terminal中输入**source xxxx.csh**。其实有这个就足够的,仔细阅读这篇文章对于编写或者修改cshell脚本有较大的帮助。
# shell selection(shell类型选择)
通常在cshell脚本的第一行,我们需要指明脚本的类型,这有助于UNIX系统去解析对应的脚本。换句话说,系统需要知道用户source的脚本是哪一种类型的,是perl,bash,cshell还是TCL(关于TCL的知识还在学习当中,后续会慢慢的更新)
```bash
#!/bin/csh #注释:正常情况下写这一条代码就可以了,因为bin目录下一般会存在csh。
```
有了前面铺垫后,下面开始进入正题:
# 变量
cshell的变量可以分为标量,数组和特殊变量。
1. 标量(scalar)
**set**是给标量赋值的关键字。cshell中没有字符串,整型,负数以及浮点型的区别,统一使用set为标量赋值,下面看几个例子。
```bash
set colour = blue
set title = "hello world"
set float_dat = 1.23E-09
set int_dat = 9
set int_dat_s = -9
```
由此可知,设置变量的范式如下所示。
```bash
set VAR_NAME = VALUE #VAR_NAME: 标量名称;VALUE:标量值
```
另外,在某些情况下可能需要移除某个标量,被移除的标量不能在后续的程序中使用。cshell脚本中使用**unset**便可实现。如移除colour。
```bash
set colour = blue
#标量参与了某件事情的处理
unset colour
#由于使用unset移除了colour,因此后续不能在使用 colour这个标量
```
值得注意的是:unset支持字符匹配的方式,表示匹配的标量都会被移除,如下所示。
```bash
unset iso_* #表示移除名称是以iso_为前缀的所有标量,如iso_a,iso_1, iso_1234等。
```
另外,可能还有**setenv**这个关键字,该关键字表示设置系统标量,即整个系统都可以看见。移除某个系统标量的关键字为**unsetenv**。那么两者的区别是什么呢?**set**和**setenv**两者的区别为:可见的范围不同。
- set定义的标量仅仅是当前脚本可见。
- setenv定义的变量是系统可见,可以用echo输出系统标量,即echo $SYS_VAR_NAME
个人建议少用系统标量,要用也应该避免和系统中以后的标量名重复。即,假设系统中有一个标量的名字为SYS,如果我们在编写xxx.csh脚本时,一步小心写setenv SYS = 1, 那么source xxx.csh后,原本的SYS将变成1,覆盖了之前的值,这可能是灾难性的后果。
这里介绍一个使用系统标量的实际案例。有些场景中需要在cshell中调用TCL,并且不是直接调用,中间可能还包了一层或者几层的其他脚本,如Makefile。然而,我们需要把cshell中的某个标量值传递给TCL,为了简单起见且修改最少的内容,我们可以把需要传递的标量定义为系统标量,这样在TCL中我们就可以直接使用。
```bash
setenv SWCH_ME = "ON" # 定义系统标量SWCH_ME
# 下面是TCL语句
set SWCH = $ENV{SWCH_ME} #TCL中引用系统标量SWCH_ME
```
我想关于标量的描述有这些就够了。
2. 数组(array)
数组可以简单的理解为多个标量组合。即通过括号将多个标量组合起来,并且使用**空格**作为分隔符。其中,一个数组里面可以包含不同类型的标量,如整型,浮点型,字符型等。另外如果数组中包含了带空格的字符串,那么一定需要使用双引号将字符串包起来,否则字符串会被解析器认为是数组中的多个元素。简单示例如下所示。
```bash
set coluors = (blue yellow green red pink)
set misc = ("hello world" blue 3 -4 1.34E09)
```
其中,hello world不采用“”包起来的话,那么解析器就会认为hello是数组misc的一个元素,world也是数组的一个元素。
数组的范式如下所示:
```bash
set ARR_NAME = (ELEM1 ELEM2 ELEM3)
```
定义好数组后,更加关键的是如何使用。下面以一个实例详细的介绍数据的使用。
定义一个数组prime:
```bash
set prime = (1 2 3 4 5 6 7 8 9)
# $#prime的结果为9;
# $prime[*]的结果为:1 2 3 4 5 6 7 8 9;
# $prime[$]的结果为:9;
# $prime[3-5]的结果为:3 4 5;
# $prime[8-]的结果为:8 9
```
总结如下所述:
- $#ARR_NAME表示数组的长度,即数据包含几个元素。
- $ARR_NAME[*]表示数组的所有元素
- $ARR_NAME[\$]表示数组的最后一个元素。[Note: $通常都是用来表示最后一个object]
- $ARR_NAME[M-N]表示数组的第M到第N个元素。其中,**数组的索引下标是从1开始,而不是0**;“-”是连接符。
- $ARR_NAME[M-]表述数组的第M到最后一个元素。
某些场景下会使用到数组的拼接。如ARR1和ARR2拼接获得ARR3。如下所示:
```bash
set ARR1 = (1 2 3)
set ARR2 = ("hello world" blue)
set ARR3 = ($ARR2 $ARR1) # ARR3的结果为"hello world" blue 1 2 3
```
上述实例仅仅展示两个数组的拼接(应用了数组的所有元素),当然还可以选择数组的有个元素进行拼接。如下所示:
```bash
set ARR1 = (1 2 3 4 5 6)
set ARR2 = ("hello world" blue red yellow green)
set ARR3 = ($ARR2[1] $ARR1[3] $ARR1[4]) # ARR3的结果为 1 red 4
```
3. 特殊字符(special characters)
cshell定义了一些特殊的字符,或者称为元字符。如:**\***, **?**, **[]**,**''**, **""**, **()**以及 **\**。下面将逐个介绍:
- *:通配符之一,表示任意多个字符。通常和unset搭配使用,如:unset iso_\*(移除iso_为前缀的所有标量)
- ?: 通配符之一,表示任意一个字符。通常和unset搭配使用,如:unset iso_?(移除iso_为前缀且"_"后只有一个字符的标量)
- []: 用于数组的索引。如:ARR1[1](索引数组的第一个元素)
- ''(单引号):1.用于定义字符串(不推荐使用),如:'hello world'。2. **用于包装命令,即让某些命令先执行**(比较常见的一种使用方式)。如:set VAR = 'echo $usr' 表示将标量usr的值赋值给标量VAR。其中usr为系统预定义的标量,后面将会介绍。
- ""(双引号):用于定义字符串,如"hello world"。
- (): 用于定义数组或者其他的语句结构,如if...then结构
- \\: 1. 转义元字符,如字符串中想表示*(星号),则采用\\*。2. 用于长命令的连接,如一条命令太长了,想要分两行写,目的是便于阅读。其中,所有的元字符都可以使用“\”进行转义。
**另外**:特别说明一下单引号和双引号定义定义字符串是的区别。如下所示:
```bash
set five = 5
set VAR = 'Give me $five' # VAR的结果为:Give me $five
set VAR2 = "Give me $five" # VAR2的结果为:Give me 5
```
明白了吧,换句话说,**单引号内的部分的元字符不具有特殊含义,双引号内的元字符仍旧具有特殊的含义。**我个人不建议使用单引号定义字符串,没有必要为难自己。单引号就单独用来包装命令就好了。
4. 特殊变量(special variable)
5. cshell 预定义的变量(predefine variable)
# 字符
# 文件处理
# 基本语法结构
## echo
## if
## if...elseif
## 循环
### while
### foreach
## switch
## shift