shell 编程

一、shell 编程概述

在 Linux 下有一门脚本语言叫做:Shell 脚本,这个脚本语言可以帮助我们简化很多工作,例如编写自定义命令等,所以还是很有必要学习它的基本用法的。

本质上讲,shell 是 linux 命令集的概称,是属于命令行的人机界面。shell 里语句可以直接是 linux 命令的执行。

shell分为几个版本,Bourne Shell, C Shell,Bash (Bourne Again Shell),Korn Shell,Z Shell 等版本。

常用的 shell 主要有两种:Bash 和 C Shell,特点如下:

  • Bash 是 GNU 项目的一部分,是最广泛使用的 Shell 之一。
    • 完全兼容 Bourne Shell,并扩展了大量功能,如命令行编辑、命令补全、历史记录等。
    • 支持函数定义、数组操作、关联数组(从版本 4 开始)等高级特性。
    • 非常适合脚本编写和日常使用,是 Linux 系统默认的 Shell。
    • 在 linux 中,默认的环境配置文件路径在~/.bashrc,用户在登录后,默认执行该配置。
  • C Shell 提供一种更接近于 C 语言语法的脚本环境。
    • 支持命令历史记录、别名、文件名补全等功能,提高了交互效率。
    • 提供了一些类似于 C 语言的控制结构(如 ifswitch),便于熟悉 C 的开发者使用。
    • 不适合复杂的脚本编程,因为它的变量处理不如 Bash 灵活。
    • 在 linux 中,默认的环境配置文件路径在~/.cshrc,用户在登录后,默认执行该配置。

二、开始 Bshell

shell 语言是 linux 命令集的概称,shell 可以通过其条件语句和循环语句等,把一系列 Linux 命令结合在一起,形成一个相当于面向过程的程序。

同时,在语法上,shell 语言格式与其他编程需要有相当大的不同。这个做一个简单的总结:

  • 用 # 进行单行注释,也可多行注释,多行注释请百度,一般用的少
  • 用空格分割命令,空格不能随便用
  • 用换行分割语句,分号也可用来分割语句。语句可以是一个命令,也可以是一个关键词。
  • 对缩进没有要求,但是尽可能好看点,便于阅读

一个简单的 hello.sh 脚本像下面这样:

#!/bin/bash                     # 标识该 Shell 脚本由哪个 Shell 解释

echo "Hello World!"             # 打印输出字符 Hello World!

运行 shell 脚本:在 CMD 命令行下,sh hello.sh 即可,也可 ./hello.sh 运行

后台运行sh hello.sh & ,若退出终端的运行就会挂掉。

后台挂起运行nohup sh hello.sh &,hohup 的作用是:用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行。

Shell 的编写流程:

  1. 编写 Shell 脚本
  2. 赋予可执行权限(一般可以忽略)
  3. 执行,调试

2.1 shell 关键字

所有的 linux 命令都可以在 shell 脚本里直接使用,比如:

#!/bin/bash

input=`ls ./teat/*`  #`` 是反引号,通常位于 esc 键下面,用于执行 linux 的 ls 命令并返回结果

除此之外,bshell 还有以下关键字用于脚本编写。

2.1.1 基本关键字

基本常用的关键字如下:

  1. echo:打印文字到屏幕
  2. exec:执行另一个 Shell 脚本
  3. read:读标准输入
  4. expr:对整数型变量进行算术运算
  5. test:用于测试变量是否相等、 是否为空、文件类型等
  6. exit:退出

看个例子,新建文件 test.sh,写入:

#!/bin/bash 

echo "Hello Shell"       # 打印输出字符串 Hello Shell

# 读入变量(从屏幕输入)
read VAR
echo "VAR is $VAR"     

# 计算变量
expr $VAR - 5       #算术运算,并返回值

# 测试字符串
test "Hello"="HelloWorld"

# 测试整数
test $VAR -eq 10

# 测试目录
test -d ./Android

# 执行其他 Shell 脚本
exec ./othershell.sh

# 退出
exit

$ 符号是对变量取值

2.1.1 各种重要符号

  • $ 变量名:对变量取值

  • ${ 变量名 }:对变量取值,花括号的作用仅仅是精确界定变量名称的范围。

  • $(命令或函数名):执行命令或函数,并返回执行结果。与反引号 ` 命令或函数名 ` 作用一致

  • 引号:见 2.2.1 章节

  • $[1+2]$((2+1)):进行整数运算,注意这里可以没有空格

  • []:条件判断符号,用于条件测试,见 2.5 章节

  • (()):仅仅用于整型数字的计算与比较

  • [[]]:双方括号为字符串比较提供高级功能,模式匹配。常见用法见 2.4.2。[[是 bash 程序语言的关键字。

  • 分号或换行,一个 / 一句命令的结束


()与 {} 的区别

相同点:

  • ()和 {} 都是把一串的命令放在括号里面,如果命令在一行,则命令之间用 ; 隔开

不同点:

  • ()只是把一串命令重新开一个子 shell 进行执行,不影响当前 shell 环境;{}对一串命令在当前 shell 执行, 影响当前 shell 环境

  • ()最后一个命令不用分号,{}最后一个命令要用分号

  • ()里的第一个命令和左边括号不必有空格,{}的第一个命令和左括号之间必要要有一个空格

  • ()和 {} 中括号里面的某个命令的重定向只影响改名了,但括号外的重定向则影响到括号里的所有命令


== 与 = 的区别

  • == 可用于判断变量是否相等,= 除了可用于判断变量是否相等外,还可以表示赋值。
  • = 与 == 在 [] 中表示判断 (字符串比较) 时是等价的
  • 在 (()) 中 = 表示赋值, == 表示判断(整数比较),它们不等价

${}的补充用法

  • ${var:-word}:若 var 为空或未设置,返回默认值但是并不把默认值赋值给该变量,若 var 不为空,则不替换,var 的值不变
  • ${var:=word}:若 var 为空或未设置,把默认值赋值给该变量。若 var 设置了,则不替换,var 的值不变
  • ${var:+word}:若 var 不为空时,返回默认值,并且也不重新赋值

2.2 字符串

shell 就两种数据类型,字符型和数组。数字(整型)也可以看作是一种字符串。

在 Shell 中所有的变量默认都是字符串型。字符串可以用单引号,也可以用双引号,也可以不用引号。

字符串赋值时,变量名和等号之间 不能有空格

取值时,只要在变量名前面加美元符号 $ 即可,也可使用 ${变量名}

2.2.1 引号

  • 单引号

    str='this is a string'

    单引号字符串的限制:

    • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
    • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
  • 双引号

    name="Jack"
    str="my name is $name"

    双引号的优点:

    • 双引号里可以有变量
    • 双引号里可以出现转义字符
  • 不加引号

    path=/home/qiang/
    
    file=$path/xor.txt

    不加引号特点:

    • 只能是连续字符串,不能有空格
    • 可以有变量
    • 可以出现转义字符

这里补充一个符号:反引号 `

这个符号通常位于键盘 Esc 键的下方。当用尖角号括起来一个 shell 命令时,代表执行这个命令,并将执行的结果返回给赋给的变量。

2.2.2 字符串方法

  • 获取子串长度${#str},获取 str 变量的字符串长度

  • 提取子串(切片):${str:1:4},从第 2 个字符开始,截取 4 个字符

    • ${str:2},从第 3 个字符开始,截取后面所有字符

    • ${str:2:-1},从左往右第 3 位开始截取,从右往左截取到第一位

  • 查找子串

    expr index "$str" xy    #查找字符 x 或 y 的位置(哪个字母先出现就计算哪个)
  • 拼接字符串"hello, ""$name",直接写在一块就行。

  • 字符串替换${var/pattern/replacement}

  • 匹配删除

    • 直接匹配:

      语法 说明
      ${str#hello} 如果 str 以 hello 为开头就删掉 hello
      ${str%hello} 如果 str 以 hello 为结尾就删掉 hello
    • 通配符匹配:

      语法 含义 示例(var=”a_b_c.txt”) 结果
      ${var# 模式 } 从开头删,最短匹配 ${var#*_} b_c.txt
      ${var## 模式 }** 从开头删,最长匹配 ${var##*_} c.txt
      ${var% 模式 } 从结尾删 最短匹配 ${var%.txt} a_b_c
      ${var%% 模式 } 从结尾删 最长匹配 ${var%%.*} a_b_c
    • 通配符:

      通配符 含义
      * 匹配任意字符(包括空)
      ? 匹配任意单个字符
      [abc] 匹配 a、b 或 c
      [0-9] 匹配数字

2.3 shell 变量类型

Shell 变量分为 3 种:

  1. 用户自定义变量
    • 等号前后不要有空格:NUM=10
    • 一般变量名用大写:M=1
  2. 预定义变量
  3. 环境变量

2.3.1 自定义变量

这种变量 只支持字符串类型,不支持其他字符,浮点等类型,常见有这 3 个前缀:

  • unset:删除变量
  • readonly:标记只读变量
  • export:指定全局变量

一个例子:

#!/bin/bash 

# 定义普通变量
CITY=SHENZHEN              #将字符串 SHENZHEN 赋给变量 CITY 

# 定义全局变量
export NAME=cdeveloper     

# 定义只读变量
readonly AGE=21

# 打印变量的值
echo $CITY
echo $NAME
echo $AGE

# 删除 CITY 变量
unset CITY

2.3.2 预定义变量

预定义变量常用来获取命令行的输入,有下面这些:

  1. $0 :脚本文件名
  2. $1-9:第 1-9 个命令行参数名
  3. $#:命令行参数个数
  4. $@ :所有命令行参数
  5. $* :所有命令行参数
  6. $? :前一个命令的退出状态,可用于获取函数返回值
  7. $$ :执行的进程 ID

在运行 shell 脚本的时候,可以外部传参,供脚本内部使用:

sh test.sh param1 parma2 parma3     #运行 test.sh 脚本并传入三个参数 param1 parma2 parma3

这时候这 7 个预定义变量的作用就容易出来了。

一个例子执行sh.test.sh x y z

#!/bin/bash

echo $0         #输出 test.sh
echo $1         #输出 x
echo $2         #输出 y
echo $3         #输出 z
echo $#         #输出 3
echo $@         #输出 x y z
echo $*         #输出 x y z
echo $?         #输出 0
echo $$         #输出 184715

2.3.3 环境变量

环境变量默认就存在,常用的有下面这几个:

  1. HOME:代表用户主目录
  2. PATH:代表系统环境变量 PATH
  3. TERM:代表当前终端
  4. UID:代表当前用户 ID
  5. PWD:代表当前工作目录,绝对路径

看一个例子:

#!/bin/bash

echo "print env"

echo $HOME    #输出 /home/origin
echo $PATH    #输出 /home/orange/anaconda2/bin: 后面还有很多
echo $TERM    #输出 xterm
echo $PWD     #输出 /home/origin/test
echo $UID     #输出 1674

2.4 shell 运算符

由于 Shell 中所有的变量默认都是字符串型,故在运算时,不同于常规运算方法。

2.4.1 算术运算

shell 的算术运算只支持整型数字运算(包括正负整型),不支持浮点数。

在算术运算时,非数字的单字符或字符串都被 shell 当作 0。

常用的四种运算格式(都是计算 m+10):

  • m=$[m+10]
  • m=$((m+10))
  • let m=m+10 #除了 let 后面有空格,计算中必定不能存在空格,只能赋值,不能直接输出
  • 利用 expr 命令

举例说明:

#!/bin/sh

aa=10

bb=$((aa+10))
bb=$[aa+10]
let bb=aa+10
bb=`expr $aa + 10`

if ["$aa" == 10]; then  # “10” 加引号也可
    ((aa++))
fi
echo $aa   #输出 11

支持的运算符如下:

  • 加号(+)、减号(-)、乘法(*)、除法(/)、取余(%)、赋值(=)、自增(++)、自减(–)

小数(浮点数)运算

  • 利用 bc 模块
    • bcLinux 下的计算机工具模块,bc支持 交互式 非交互式 两种计算,在进行计算的时候,可以使用 scale=n 来指定小数点的位数,还支持比较操操作符>、>=、<、<=、==、!=
    • 交互式:打开 bc 计算机,进行使用。
    • 非交互式:通过脚本命令执行,不需要打开计算机。
    • 在使用 bc 命令时如果报错 bc: command not found,说明没有安装此工具模块,需要进行安装:
  • 利用 awk 模块

举例:

#!/bin/bash

echo "scale=2;10/3" | bc   #scale=2 是保留两位有效小数,计算 10/3 的值

result=`echo "scale=2;10/3" | bc`

#------ 传参, 2 种方式
result=$(bc -l <<< "scale=2;$a * $b")

result=`echo "$a + $b" | bc`

#----- awk, awk 传参麻烦,不建议用
awk 'BEGIN { print 3.14 + 2.86 }'
awk 'BEGIN { printf "%.2f\n", 10 / 3 }'   # 保留两位小数

2.4.2 逻辑运算符

运算符 说明 举例
&& 逻辑 AND [[$a > 0 && $b < 10]]
|| 逻辑 OR [[$a >= 0 || $b < 10]]

特点:

  • 短路求值:如果 command1 失败,command2 不会执行
  • 用于命令流程控制,不是专门用于条件测试。

举例:

#!/bin/sh

index=0
file="test.txt"

#---- 写法 1
if [[$index == 0 && -f $file]]; then
    echo "hello" > $file
fi

#---- 写法 2
if [$index == 0] && [-f $file]; then
    echo "hello" > $file
fi

#---- 写法 3
if ((index > 0)) && [-f "$file"]; then
    echo "hello" > $file
fi

2.4.3 布尔运算符

运算符 说明 举例
取反运算 [! -f $file]

这里只需要记住这个即可,其他的布尔运算符不建议用。

2.5 条件测试

shell 条件测试一共就三种: 文件测试 数值比较 字符串比较

条件测试分为三种用法,但作用是一样的:

  • test 条件表达式
  • [条件表达式]
  • [[条件表达式]]

推荐使用第二种。

2.5.1 文件测试

用法示例:

[! -d /home/test] && makdir /home/test     #目录不存在就创建

[-d /home/test] || makdir /home/test     #目录存在就不创建

test -d /home/test
echo $?
0                     #在 shell 中,为真的退出状态码为 0,为假时状态码为 1

2.5.2 数值比较

关系运算符只支持 整数运算,不支持字符串,除非字符串的值是数字。

  • []test 中同时支持自 字母 符号 运算符
  • (()) 仅仅使用 符号 运算符
字母运算符 符号运算符 示例 说明
-eq == ["$a" -eq "$b"]((a == b)) 等于
-ne != ["$a" -ne 5]((a != 5)) 不等于
-lt < ["$a" -lt 10]((a < 10)) 小于
-le <= ["$a" -le 10]((a <= 10)) 小于等于
-gt > ["$a" -gt 0]((a >= 0)) 大于
-ge >= ["$a" -ge 100]((a >= 100)) 大于等于

必须用双引号包裹变量(防止空值导致语法错误)

["$count" >= 5]   # ✅ 安全
[$count >= 5]     # ❌ 若 count 为空,会报错

浮点数比较

a=3.14
b=2.71

#---- 比较 a > b ?
if ["$(echo "$a > $b" | bc)" = "1" ]; then
    echo "a 大于 b"
fi

2.5.3 字符串比较

字符串变量要使用双引号引起来

用法示例:

cha="aa"

if ["$cha" == "aa"]; then
    echo "is aa"
fi

2.6 shell 语句

2.6.1 if 语句

格式:

if 条件测试 1 ; then
   执行语句 1
elif 条件测试 2; then
   执行语句 2   
else
   执行语句 2
fi

用法示例:

#!/bin/bash 

VAR=10

if [$VAR == 10]; then
    echo "true"
else
    echo "false"
fi

2.6.2 case 语句

格式:

case $ 变量 in
    值 1)
      执行语句 1
      ;;
    值 2)
      执行语句 2
      ;;
    *)
      执行语句 3
      ;;
esac    

2.6.3 for 语句

格式:

#--- 格式 1
for ((i = 1; i <= 3; i++))
do
    echo $i
done

#--- 格式 2
for j in 1 2 3
do
    echo $j
done

#--- 格式 3
for j in {0..100}    #输出 0-100
do
    echo $j
done

workspace="/home/user1/project"
input=`ls ./teat/*.gg`
for ff in $input
do
    out="$workspace/$input"
    echo $out
done

2.6.4 while 语句

格式:

while 条件测试       #条件为真,执行
do
    执行语句  
done

2.6.5 until 语句

格式:

until 条件测试       #条件为假,执行
do  
    echo $i
    i=$[$i + 1]
done

2.6.6 break

Shell 中的 break 用法与高级语言相同,都是 跳出循环,来看个例子:

for VAR in 1 2 3
do
    if [$VAR == 2]
    then
        break
    fi

    echo $VAR
done

2.6.7 continue

continue 用来 跳过本次循环,进入下一次循环

for VAR in 1 2 3
do
    if [$VAR == 2]
    then
        continue    
    fi

    echo $VAR
done

2.7 shell 数组

shell 就两种数据类型,字符型和数组。字符串之前已经介绍了,这里介绍数组。

数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小。

2.7.1 数组定义

# ---- 第一种
arr=(v1 v2 v3 v4 v5)    #v 可以是字符串或者数字,不必类型相同

#---- 第二种
arr1=(
xxx
yyy
zzz
)

#---- 数组的遍历
for case in ${arr1[*]}
do
  echo $case
done

#----- 单独赋值
arr[1]=10

#---- 第三种: 用字符串实现同样的功能
arr2="
xxx
yyy
zzz
"
#----- 字符串的遍历
for item in $arr2
do
    echo $item
done

一对括号 (…) 表示的是数组,数组元素用空格符号分隔开

数组和字符串循环取值的方式不同,注意区分

2.7.2 读取与赋值

  • 读取数组:
    • 读取整个数组:${arr[@]} 或者 ${arr[*]}
    • 按索引读取:${arr[index]},索引从 0 开始
  • 读取长度:${#arr[@]} 或者 ${#arr[*]}
  • 赋值:arr[1]=100
  • 删除:unset arr[1]unset arr
  • 替换:${a[@或 *] / 查找字符 / 替换字符 } ,该操作不会改变原来的数组内容

一个常用的例子:

caselist=($(ls /home/template_dir | grep -v 'xor'))

for case in ${caselist[*]}
do
  echo $case
done

2.8 shell 函数

shell 函数中,默认均为全局变量,如想用局部变量加local 关键字

2.8.1 函数定义与调用

格式 1:

function fun1(){         #如果写了 function 关键字,()可以省略

   echo $1       #返回方式 1
   echo $2
   return 0      #返回方式 2

}

#1 直接函数名调用, 并传参
fun1 10 20

#2 间接调用
F=`fun1 100 200`
echo $F

格式 2:

fun2()
{
  echo "fun2 call"  
}

#3 直接函数名调用,不带参数方式
fun2

Shell 函数返回值,常用的两种方式:return、echo。二者是有差别的

  • return:只能用来返回整数值(0-255),一般是用来表示函数执行成功与否的,0 表示成功,其他值表示失败。
  • echo:标准输出返回,可以返回任何类型的数据。

2.8.2 获取函数返回值

  • 函数用 echo 输出返回:直接函数名调用

  • 函数用 return 输出返回:$? 接收,$?要紧跟在函数调用处的后面

先举个例子:

fun2()
{
  echo "fun2 call"
  return 100
}

fun2        # 输出 echo 的内容:  fun2 call

echo $?      #输出 return 的内容:100

echo $?      #输出函数退出码:0

还有 2 种:

  • 函数名当命令执行:`fun2` (尖角号) 或者 $(fun2)
  • 传参输出返回:$(fun2 “/temp”)

再举个例子:

fun3()
{
  echo "fun3 call"
}

echo `fun3`      #输出打印 fun3 call

echo $(fun3)     #输出打印 fun3 call

re=$(fun3) 

echo ${re}       #输出打印 fun3 call

2.8.3 高级收参

$@ 可以接收所有参数,以数组的方式。

function getsum(){
    local sum=0
    for n in $@
    do
         ((sum+=n))
    done
    echo $sum
    return 0
}

total=$(getsum 10 20 55 15)
echo $total

2.9 shell 重定向

2.9.1 输出重定向

命令的结果不再输出到显示器上,而是输出到指定的文件里。

  • 命令输出重定向

格式:

command > file       #覆盖写入到文件
command >> file      #追加写入到文件 

用法示例:

echo "hello world!" > data.txt

ls -l >> data.txt
  • cat 输出重定向 用于多行文本写入

用法示例:

cat > file << EOF
export ORACLE_SID=yqpt 
export PATH=\$PATH:\$ORACLE_HOME/bin  
EOF

作用:将两个 EOF 之间的内容输出写到 data.txt 文件里。

  1. EOF 只是一个标识符,也可使用其他字符代替
  2. 多行文本如有 $ 等特殊字符时,须利用转义字符 \

2.9.2 输入重定向

使用文件作为命令的输入。

command < file       #将 file 文件中的内容作为 command 的输入
command << END       #从标准输入(键盘)中读取数据,直到遇见分界符 END 才停止 

高级用法(代码输入重定向)示例:

#!/bin/bash
sum=0
while read n; do
    ((sum += n))
done < nums.txt      #输入重定向
echo "sum=$sum"

2.10 shell 调试

检查是否有语法错误:

sh -n script_name.sh

执行并逐步调试 shell 脚本:

sh -x script_name.sh

带有 + 表示的是 Shell 调试器的输出 不带 + 表示我们程序的输出

csh 同样支持逐步调试!使用csh -x test.sh

三、开始 Cshell

csh 缺乏函数,局部变量等一些高级特性,但是在芯片及其相关软件应用上(Linux 环境),仍然非常广泛,时常需要用其写一些自动化脚本来执行任务,所以本章也对其做一个较为详细的介绍。

1. 变量声明

#!/bin/csh

#====== 使用 set 声明变量
set enc = "this is a test!"
set ax = 10   # csh 变量赋值只支持整数,不支持小数,需要额外的手段

echo $enc
echo $ax

2. 数组与循环

csh(C Shell) 中,没有真正意义上的“数组”类型 (不像 bash 有索引数组或关联数组),但 csh 和其增强版 tcsh 支持一种称为“单词列表”(word list)的变量形式,可以 模拟简单的一维字符串数组

#!/bin/csh

set myarr = ("aa" "bb" "cc")

echo $myarr[1]  #index 从 1 开始
echo $#myarr    #输出元素个数

foreach el (${myarr})

    set out = $el

end

多行的写法:

set aa = (\
test1.txt \
test2.txt \
test3.txt \
)

多行的写法只能是这样,没有更加优雅的方法。

3. 环境配置与别名声明

一般 csh 的默认配置文件为:~/.cshrc,可以在里面配置一些环境。

setenv PATH /home/user1/install/   #配置环境变量

alias .. "cd .."    #别名(快捷命令)
alias python "/home/user1/install/python3.10"

4. 逻辑判断与循环语句

4.1 if 判断

#!/bin/csh
set num = 5

if ($num == 1) then
    echo "Number is 1"
else if ($num == 2) then
    echo "Number is 2"
else if ($num == 3) then
    echo "Number is 3"
else
    echo "Number is not 1, 2, or 3"
endif

4.2 循环语句

#!/bin/csh

#======== foreach
set myarr = ("aa" "bb" "cc")
foreach el (${myarr})
    set out = $el
end

foreach folder (test1 test2 test3)
  if (! -d $folder) then
          mkdir -p $folder
  endif
end

#======= while
set sum = 0
set i = 1
while ($i <= 5)
    set sum = `expr $sum + $i`
    set i = `expr $i + 1`
end
echo "Sum is $sum"

#=========switch
switch ($sum)
  case 1: 
    # commands
    breaksw
  case 2:
      #commands
  default:
    breaksw
endsw

想其他语言一样,csh 的循环体同样支持 breakcontinue

  • break:跳出终止当前循环
  • continue:跳过本次循环剩余部分,开始下一次循环迭代

5. 写文件

写文件也叫数据重定向,使用尖括号> filePath

#!/bin/csh

#====== 单行重定向
echo "this is a test" > tt.log

#====== 多行重定向
set words = ("test1" "test2" "test3")
cat > tt.log << END
this is a $words[1]
this is a $words[2]
this is a $words[3]
END

6 数据运算与条件判断

6.1 数据运算

数据分为:数字,字符串。下面分别介绍数字运算和字符串处理方法

6.1.1 原生算数表达式:

@ c = $a + $b
@ d = $c * 2
@ e = $d / 3
@ f = $d % 4
  • 支持的运算符:+, -, *, /, %,+=, -=,++, --
  • 不支持括号嵌套复杂表达式(如 @ x = ($a + $b) * 2 会报错)
  • 所有操作必须在 @ 行内完成,不能直接在 set 中做算术

举例:

#!/bin/csh
set x = 7
set y = 3
@ sum = $x + $y
echo "Sum is $sum"

6.1.2 扩展算数

借助外部工具,还可以采用其他的方式:

#==== expr 命令,整数运算
set sum = `expr $a + $b`
set product = `expr $a \* $b`

#==== bc 命令,小数计算
set result = `echo "scale=2;10/3" | bc`   #scale=2 保留两位小数
echo $result

# ==== awk 命令,实数运算
set pi = `awk 'BEGIN {print 22/7}'`
echo "Approx pi = $pi"  #输出:3.14286

6.1.3 字符串运算

  • 字符串拼接:写一行写一块就行

    set first = "John"
    set last = "Doe"
    
    #===== 形式 1
    set full = "$first $last"
    
    #===== 形式 2
    set aa = "hhhha"`basename "test.txt" .txt`
  • 字符串长度:无内置命令,需要借助外部命令

    set str = "hello"
    set len = `echo -n "$str" | wc -c`
    echo "Length: $len"
  • 子串提取:无内置命令,可借助 awk/cut/sed

    set s = "abcdef"
    set sub = `echo "$s" | cut -c2-4`   # 提取第 2 到第 4 字符
    echo $sub   # 输出:bcd

6.2 条件判断

6.2.1 数值与字符串判断

#===== 数值判断
set x = 10
if ($x > 5) then
    echo "x is greater than 5"
endif

#===== 字符串判断
set name = "Alice"
if ("$name" == "Alice") then
    echo "Hello, Alice!"
else
    echo "Who are you?"
endif

数值支持:==、!=、<、<=、>、>=

字符串支持:==、!=

6.2.2 文件判断

使用 csh 可以直接对文件或者路径进行判断:

#!/bin/csh
# 定义文件名
set filename = "test.txt"

#===== 判断文件是否存在
if (-e $filename) then
   echo "$filename 存在 "
else
   echo "$filename 不存在 "
endif

文件 / 文件夹判断方法总结如下:

表达式 含义
-r file 文件存在且可读
-w file 文件存在且可写
-x file 文件存在且可执行
-e file 文件存在(任何类型)
-f file 文件存在且是普通文件
-d file 文件存在且是目录
-c file 字符设备文件
-b file 块设备文件
-p file 命名管道(FIFO)
-l file 符号链接(部分实现支持)
-u file 设置了 setuid 位
-g file 设置了 setgid 位
-s file 文件存在且非空(size > 0)

6.3 逻辑运算

运算符 含义 示例
&& 逻辑与(AND) if ($a > 0 && -f "$file") then
` `
! 逻辑非(NOT) if (! -e "$tmp") then

必要时用括号明确顺序(但注意 csh 对复杂嵌套括号支持有限):

if (( $a == 1 || $a == 2) && -f "data$a.txt" ) then
    ...
endif

欢迎各位看官及技术大佬前来交流指导呀,可以邮件至 jqiange@yeah.net