KSH语法

本文出自:https://blog.csdn.net/shangboerds/article/details/48623533

一大佬总结,膜拜一下!

注意事项

  • if[[]] []内两边要有空格

    #例:
    if[[ $a -eq 1 ]] 
    #反例: 
    if[[$a -eq 1]]
    
  • 赋值=两边最好不要空格

    #例:
    d=`date %Y%m%d` 
    #反例:
    d = `date %Y%m%d`
    

示例

#!/bin/ksh 
print "Hello World.";

第一行代码称为沙邦(sh-bang),表示由什么程序运行此脚本。
第二行的 print 是一个命令,用来打印输出。

注释

## 这里是单行注释,单行注释以 ## 开始到行尾。

:<<!
这里是多行注释,! 可以是任何成对的字符
!

命令分隔符

通常,ksh 认为每一行就是一个命令或语句,如果一行包含多条语句,你可以在语句之间加上分号(😉。当然,你也可以在每一行后面加上分号。

变量

常量

#!/bin/ksh
## 定义常量方法 1
typeset -r CONSTANT_INT=110;

## 定义常量方法 2
readonly CONSTANT_STR="TEST";

数值

## 定义整数变量
integer var_int1=10; ## 方法 1(推荐)
typeset -i var_int2=-10; ## 方法 2
let "var_int3=20"; ## 方法 3
((var_int4=30)); ## 方法4
integer var_int5=010; ## 八进制以 0 开头
integer var_int6=0x10; ## 十六进制以 0x 开头

#--- 2## 表示后面的数字是二进制
#--- B#N B表示进制,最大 64
integer var_int5=2#10;

## 定义浮点数变量
float var_float1=250.0; ## 方法 1(推荐)
typeset -F var_float2=250.; ## 方法 2
typeset -F var_float3=0.25;
typeset -F var_float4=.25;
typeset -F var_float5=-250.0e2; ## -250.0乘以 10 的 2 次方,e不区分大小写

## typeset -E 用来定义双精度浮点数变量
typeset -E var_double1=250.0;
typeset -E var_double2=250.;
typeset -E var_double3=0.25;
typeset -E var_double4=.25;
typeset -E var_double5=-250.0e2; ## -250.0乘以 10 的 2 次方,e不区分大小写

字符串

## 方式1:双引号  
## 双引号内的字符串可以进行变量插值和字符转义  
typeset str="Zhang San";  
typeset string="Li Si";  
typeset text1="my name is $str\n"; #此处的 $str 将被字符串张三替换,这种能力称之为变量插值,\n 为转义字符  
typeset text2="my name is $string\n"; ## 此处的变量到底是 $str 还是 $string 呢?默认是最长匹配,也就是$string  
typeset text3="my name is ${str}ing\n"; ## 如果想插入变量 $str的值,可以将变量名用大括号围起来  
  
## 方式2:单引号  
## 单引号内的任何字符都代表它自己,无法进行变量插值和字符转义  
typeset text4='my name is $str\n'; #此处的 $str 无法被替换为张三,\n 也无法代表换行符

字符串函数

########################## 长度 
## ${#xx} 得到变量 xx 的长度 
print "the length of $str is ${#str}";

########################## 子串
## ${xx:start} 从 start 开始得到变量 xx 的子串
print "Get substring from 11: ${text1:11}";

## ${xx:start:length} 从 start 开始,取 length 个字符,得到变量 xx 的子串
print "Get substring from 11 and get 5 characters: ${text1:11:5}";

## ${xx:start} 和 ${xx:start:length}, 注意 start 可以是负值哦,表示相对于字符串的末尾
print "Get substring from -9: ${text1:-9}";

########################## 替换
## ${xx/pattern/replace} pattern 是个正则表达式,将变量 xx 中 pattern 匹配的字串替换成 replace 指定的字符串,非贪婪模式 
print "text1 after replaced Zhang to Wang: ${text1/Zhang/Wang}";

## ${xx//pattern/replace} 同上,贪婪模式 
print "text1 after replaced Zhang to Wang: ${text1//Zhang/Wang}";

## ksh 不支持 行首,行尾,单词边界 正则表达式,下面的方式实现了类似功能
## ${xx/#pattern/replace} pattern 是个正则表达式,从变量 xx 开头查找 pattern 匹配的字串替,如果找到则换成 replace 指定的字符串,非贪婪模式
print "str after replaced Zhang to Wang: ${str/#Zhang/Wang}";

## ${xx/%pattern/replace} pattern 是个正则表达式,查找变量 xx 是否以 pattern 匹配的字串替结尾,如果找到则换成 replace 指定的字符串,非贪婪模式
print "str after replaced San to Four: ${str/%San/Four}";

########################## 删除子串
## ${xx/pattern} pattern 是个正则表达式,删除变量 xx 中 pattern 匹配的子串,非贪婪模式 
print "text1 after removed Zhang: ${text1/Zhang}";

## ksh 不支持 行首,行尾,单词边界 正则表达式,下面的方式实现了类似功能
## ${xx#pattern} pattern 是个正则表达式,从变量 xx 开头查找 pattern 匹配的字串替,如果找到则删除,非贪婪模式
print "str after removed Zhang: ${str#Zhang}";

## ${xx##pattern} 同上,贪婪模式
print "str after removed Zhang: ${str##Zhang}";

## ${xx%pattern} pattern 是个正则表达式,查找变量 xx 是否以 pattern 匹配的字串替结尾,如果找到则删除,非贪婪模式
print "str after removed San: ${str%San}";

## ${xx%%pattern} 同上,贪婪模式
print "str after removed San: ${str%San}";


########################## 判断是否为空
## 接收参数  
name=$1;  
age=$2;  
gendar=$3;  
description=$4;  
  
## ${xx:-"test"} 表示如果变量 xx 存在且不为 null,返回其值,否则返回  test
name=${name:-"Shang Bo"};  
print "name=$name";  
  
## ${xx:='test'} 表示如果变量 xx 存在且不为 null,返回其值,否则设置 xx 为 test 并返回 test  
age=${age:='30'};  
print "age=$age";  
  
## ${xx:+'test'} 表示如果变量 xx 存在且不为 null,返回 test, 否则返回 null  
description="a java developer";  
print "${description:+'description already defined'}";  
  
## ${xx:?"error"} 表示如果变量 xx 存在且不为 null,返回其值,否则显示 error 错误消息 并终止程序  
gendar=${gendar:?"gendar missing."};  

## -n 判断字符串不为空,长度不为0  
if [ -n "$name" ]; then  
    print "#** $name is not empty **#"  
fi  

## -z 判断字符串为空.长度为0.  
if [ -z "$x" ];then  
    print "#** $x is empty **#"  
fi 

########################## 其他
## ${!xx*} 或 ${!xx@} 得到 以 xx 开头的所有变量
print "We have variables ${!text*} who start with text";

alpha="   aBcDeFgHiJkLmNoPqRsTuVwXyZ   ";

## 去掉前面空格
typeset -L v=$alpha;
print "Remove leading spaces: $v";

## 去掉尾部空格
typeset -R v=$alpha;
print "Remove trailing spaces: $v";

## 去掉前面空格后,保留 10 位字符,如果长度不够 10 位则在尾部补空格
typeset -L10 v=$alpha;
print "truncate to 10 after remove leading spaces: $v";

## 去掉尾部空格,保留 16 位字符,如果长度不够 16 位则在前面补空格
typeset -R16 v=$alpha;
print "truncate to 16 after remove trailing spaces: $v";


## 在前面补 0 使整个数字成 8 位
typeset -Z8 v="123.50"
print "add leading 0: $v";

## 去掉前面的 0 使整个数字成 6 位
typeset -LZ6 v="00123.50"
print "strips leading 0: $v";


## 全部转成小写
typeset -l v=$alpha;
print "to lowercase: $v";

## 全部转成大写
typeset -u v=$alpha;
print "to uppercase: $v";

转义

## 转义字符
\a	响铃
\b	退格
\c  终止处理字符串
\E	Esc键
\f	换页
\n	换行
\r	回车
\t	水平制表符
\v	垂直制表符
\0n 表示n为8进制数字
\\	反斜线

作用域

## 定义函数
function fun_test {
	## 定义局部变量
	typeset local_vardefined_in_function="local variable defined in function";

	## 在函数中定义全局变量	
	global_var_defined_in_function="global variable defined in function";
	
	## 改变全局变量的值
	global_var_defined_in_main+=" changed in function";
}

## 定义全局变量
typeset global_var_defined_in_main="global variable defined in main";
print "global_var_defined_in_main=$global_var_defined_in_main";


## 调用函数
print "Call function";
fun_test;


## 打印值是否改变
print "global_var_defined_in_main=$global_var_defined_in_main";
print "global_var_defined_in_function=$global_var_defined_in_function";
print "local_vardefined_in_function=$local_vardefined_in_function";

## 结果
global_var_defined_in_main=global variable defined in main
Call function
global_var_defined_in_main=global variable defined in main changed in function
global_var_defined_in_function=global variable defined in function
local_vardefined_in_function=

变量导出

## 导出变量方法 1
typeset -x CONSTANT_INT=110;

## 导出变量方法 2
export CONSTANT_STR="TEST";

正则表达式

ksh 的正则表达式和其他语言有一些区别,最重要的区别是,在 ksh 中, ? 代表任意一个字符,* 代表任意多个字符,那么它如何匹配次数呢?看看下面的表格吧

操作符	            描述
*(exp)              贪婪匹配,匹配任意次
+(exp)              贪婪匹配,匹配 1次或多次
?(exp)              贪婪匹配,匹配 0或1次
{N}(exp)            贪婪匹配,匹配 N 次
{N,M}(exp)          贪婪匹配,匹配 N 到 M 次
@(exp1|exp2|...)    贪婪匹配,匹配 exp1 或 exp2 ...
*-(exp)             非贪婪匹配,匹配任意次
+-(exp)             非贪婪匹配,匹配 1次或多次
?-(exp)             非贪婪匹配,匹配 0或1次
{N}-(exp)           非贪婪匹配,匹配 N 次
{N,M}-(exp)         非贪婪匹配,匹配 N 到 M 次
@-(exp1|exp2|...)	非贪婪匹配,匹配 exp1 或 exp2 ...
!(exp)              匹配非 exp 的任何东西
[:word:]            匹配字母或下划线
\d                  匹配数字,同[[:digit:]]
\D                  匹配非数字,同[![:digit:]]
\s                  匹配空白字符,同[[:space:]]
\S                  匹配非空白字符,同[![:space:]]
\w                  匹配匹配字母或下划线,同[[:word:]]
\W                  匹配非匹配字母或下划线,同[![:word:]]

下面是使用正则表达式的一个简单例子。

#!/bin/ksh  

################################# 匹配
typeset brithday='2013-06-25';

if [[ ${brithday} = {4}(\d)-{2}(\d)-{2}(\d) ]]; then  
    print "legal date"  
fi  


################################# 替换
typeset str="Zhang yi, zhang er, Zhuang Si, ZHANG WU";
  
## ${xx/pattern/replace} pattern 是个正则表达式,将变量 xx 中 pattern 匹配的字串替换成 replace 指定的字符串,非贪婪模式 
print "\${xx/pattern/replace} : ${str/Z*(\w)/C\1}";

## ${xx//pattern/replace} 同上,贪婪模式 
print "\${xx//pattern/replace} : ${str//Z*(\w)/C\1}";

## ~(+i:pattern) 表示 pattern使用忽略大小写匹配模式
print "\${xx//pattern/replace} : ${str//~(+i:Z*(\w))/C\1}";


## ksh 不支持 行首,行尾,单词边界 正则表达式,下面的方式实现了类似功能
## ${xx/#pattern/replace} pattern 是个正则表达式,从变量 xx 开头查找 pattern 匹配的字串替,如果找到则换成 replace 指定的字符串,非贪婪模式
print "\${xx/#pattern/replace} : ${str/#Z*(\w)/C\1}";

## ${xx/%pattern/replace} pattern 是个正则表达式,查找变量 xx 是否以 pattern 匹配的字串替结尾,如果找到则换成 replace 指定的字符串,非贪婪模式
print "\${xx/%pattern/replace} : ${str/%?(\w)/*}";


#################################  删除子串
## ${xx/pattern} pattern 是个正则表达式,删除变量 xx 中 pattern 匹配的子串,非贪婪模式 
print "\${xx/pattern} : ${str/Z*(\w)}";

## ksh 不支持 行首,行尾,单词边界 正则表达式,下面的方式实现了类似功能
## ${xx#pattern} pattern 是个正则表达式,从变量 xx 开头查找 pattern 匹配的字串替,如果找到则删除,非贪婪模式
print "\${xx#pattern} : ${str#Z*(\w)}";

## ${xx##pattern} 同上,贪婪模式
print "\${xx##pattern} : ${str##Z*(\w)}";

## ${xx%pattern} pattern 是个正则表达式,查找变量 xx 是否以 pattern 匹配的字串替结尾,如果找到则删除,非贪婪模式
print "\${xx%pattern} : ${str%W*(\w)}";

## ${xx%%pattern} 同上,贪婪模式
print "\${xx%%pattern} : ${str%%W*(\w)}";

上面介绍的正则表达式有个缺陷,它只能匹配英语,如果你想匹配其他语言,你可以使用标准的 POSIX 语法,如下。

元字符(Metacharacter)	匹配(Matches)
[[:alnum:]]	            字母和数字
[[:alpha:]]	            字母
[[:lower:]]	            小写字母
[[:upper:]]	            大写字母
[[:digit:]]	            数字
[[:blank:]]	            空格和制表符
[[:space:]]	            空白字符
[[:graph:]]	            非空白字符
[[:print:]]	            类似[[:graph:]],但是包含空白字符
[[:punct:]]	            标点符号
[[:cntrl:]]	            控制字符
[[:xdigit:]]	        十六进制中容许出现的数字(例如 0-9a-fA-f)
[. xx .]                将 xx 作为一个整体匹配, xx 可以是任何字母
[= e =]                 认为等价,在法语中匹配 e, è, 或 é

复合变量

#!/bin/ksh  

## 定义复合变量 方法 1
zhang_san="Zhang San"
zhang_san.firstname=San
zhang_san.lastname=Zhang
zhang_san.age=18
print $zhang_san ## 简单打印

## 定义复合变量 方法 2,注意=后面的一个空格
li_si= (firstname=si lastname=li age=28);
print -r $li_si; ## 复杂打印,可读性更好

## 定义复合变量 方法 3,注意=后面的一个空格
wang_wu= (typeset firstname=wu; typeset lastname=Wang; typeset -i age=38);
print -r $wang_wu;

## 添加变量,注意+=后面的一个空格
wang_wu+= (typeset gender=man);
print -r $wang_wu;

算术运算符

#!/bin/ksh

typeset -i x=2;
typeset -i y=3;
typeset -i r=0;

## 注意,算术表达式需要包含在$(())中,否则成了文本表达式
## 注意,括号中没有 $ 哦
r=$((x+y)); #加
print "x+y=$r";

r=$((x-y)); #减
print "x-y=$r";

r=$((x*y)); #乘
print "x*y=$r";

r=$((x/y)); #除
print "x/y=$r";

r=$((x**y)); #幂,相当于2的3次方
print "x**y=$r";

r=$((x%y)); #余
print "x%y=$r";

数字比较运算符

比较数字有两种方法。

#!/bin/ksh

typeset -i x=20;
typeset -i y=3;

## 注意,数字比较时需要包含在 (())中
## 注意,括号中没有 $ 哦
## 大于
if ((x > y)); then
	print "#** $x > $y **#"
fi

if [[ $x -gt $y ]]; then
	print "#** $x gt $y **#"
fi


## 大于等于
if ((x >= y)); then
	print "#** $x >= $y **#"
fi

if [[ $x -ge $y ]]; then
	print "#** $x ge $y **#"
fi


## 小于
if ((x < y)); then
	print "#** $x < $y **#"
fi

if [[ $x -lt $y ]]; then
	print "#** $x lt $y **#"
fi


## 小于等于
if ((x <= y)); then
	print "#** $x <= $y **#"
fi

if [[ $x -le $y ]]; then
	print "#** $x le $y **#"
fi


## 等于
if ((x == y)); then
	print "#** $x == $y **#"
fi

if [[ $x -eq $y ]]; then
	print "#** $x le $y **#"
fi


## 不等于
if ((x != y)); then
	print "#** $x != $y **#"
fi

if [[ $x -ne $y ]]; then
	print "#** $x ne $y **#"
fi

字符串比较运算符

#!/bin/ksh

## ksh 支持 [] 和 [[]] 测试条件表达式,注意,它们有一些区别,推荐使用 [[]]
## 变量是否包含在双引号中也有一些区别,推荐不要使用双引号
typeset x='a';
typeset y='b';


## 判断字符串不为空
if [[ $x ]]; then
	print "#** $x is not empty **#"
fi

## 判断字符串不为空,长度不为0
if [[ -n $x ]]; then
	print "#** $x is not empty **#"
fi

## 判断字符串为空.长度为0.
if [[ -z $x ]];then
	print "#** $x is empty **#"
fi


## 等于 -- 精确匹配
if [ $x = a* ]; then
	print "#** 1 $x = a* **#"
fi

if [ $x == a* ]; then
	print "#** 2 $x == a* **#"
fi


## 等于 -- 精确匹配
if [ "$x" = "a*" ]; then
	print "#** 3 \"$x\" = \"a*\" **#"
fi

if [ "$x" == "a*" ]; then
	print "#** 4 \"$x\" == \"a*\" **#"
fi


## 等于 -- 精确匹配
if [[ "$x" = "a*" ]]; then
	print "#** 5 \"$x\" = \"a*\" **#"
fi

if [[ "$x" == "a*" ]]; then
	print "#** 6 \"$x\" == \"a*\" **#"
fi


## 等于 -- 匹配模式
if [[ $x = a* ]]; then
	print "#** 7 $x start with a* **#"
fi

if [[ $x == a* ]]; then
	print "#** 8 $x start with a* **#"
fi



## 不等于 -- 精确匹配
if [ $x != a* ]; then
	print "#** 1 $x != a* **#"
fi

if [ "$x" != "a*" ]; then
	print "#** 2 \"$x\" != \"a*\" **#"
fi

if [[ "$x" != "a*" ]]; then
	print "#** 3 \"$x\" != \"a*\" **#"
fi


## 不等于 -- 精确模式
if [[ $x != a* ]]; then
	print "#** 4 $x != a* **#"
fi



## 大于,注意:字符串没有大于等于操作符
if [[ $x > $y ]]; then
	print "#** $x > $y **#"
fi


## 小于,注意:字符串没有小于等于操作符
if [[ $x < $y ]]; then
	print "#** $x < $y **#"
fi

逻辑运算符

#!/bin/ksh

typeset x='a';
typeset y='b';
typeset z='c';

## 与
if [[ $x < $y && $y < $z ]]; then
	print "#** $x < $y < $z **#"
fi

## 或
if [[ $x < $y || $y < $z ]]; then
	print "#** $x < $y || $y < $z **#"
fi

## 非
if [[ ! $x > $y ]]; then
	print "#** $x <= $y **#"
fi

位运算符

#!/bin/ksh

## 按位与 &
## 按位或 |
## 按位非 ~
## 按位异或 ^
## 左移(相当于乘2) <<
## 右移(相当于除2) >>

赋值运算符

#!/bin/ksh

## =
## +=
## -=
## *=
## /=
## %=
## &=
## ^=
## <<= 
## >>=

typeset -i x=2;
typeset -i r=0;

## (()) 用来计算数学表达式
((r+=x));
print "r=$r";

自增自减运算符

#!/bin/ksh

typeset -i x=1;

## 自增运算符
((x++));
((++x));

## 自减运算符
((x--));
((--x));

逗号运算符

#!/bin/ksh

typeset -i x=1;

## 逗号表达式
((x++,++x));
print "x=$x";

条件运算符

#!/bin/ksh

typeset -i x=2;
typeset -i y=3;
typeset -i r=0;

((r=(y > x) ? y : x));
print "r=$r"; 

文件测试

有时候我们需要判断某个文件是否存在,很简单,使用 -e 即可,下面是一个简单例子。

#!/bin/ksh

typeset test_file="test.txt";

if [[ ! -e $test_file ]]; then  
    print "$test_file does not exist";
	exit 2;
fi

除此之外,我们还可以通过下面的操作符来测试文件的其他属性。

文件测试操作符  意义
-e              文件或目录,是否存在
-s              文件存在且不为空
-d              是否为目录
-f              是否为普通文件
-L              是否为符号链接
-r              文件或目录,对当前用户或组来说是可读的
-w              文件或目录,对当前用户或组来说是可写的
-x              文件或目录,对当前用户或组来说是可执行的
-O              文件或目录,当前用户是否是文件的拥有者
-G              文件或目录,当前用户是否和文件属于同一个组
file1 -nt file2 file1 是否比 file2 新
file1 -ot file2 file1 是否比 file2 旧
file1 -ef file2 file1 和 file2 是否是同一个文件

数组

索引数组(Indexed Arrays)

#!/bin/ksh

################################# 定义数组
## 方法 1
names[0]="Shang Bo";
names[1]="Zhang San";
names[2]="Li Si";

## 方法 2
names=("Shang Bo" "Zhang San" "Li Si");

## 方法 3
set -A names "Shang Bo" "Zhang San" "Li Si";

################################# 访问数组
print "The first element of names is ${names[0]}"; ## 取出数组下标为 0 的元素
print "names contains ${names[*]}"; ## 取出所有元素
print "names contains ${#names[*]} elements"; ## 数组长度
print "names contains ${names[@]}"; ## 取出所有元素
print "names contains ${#names[@]} elements"; ## 数组长度

################################# 操作数组
names+=("Wang Wu" "Li Qi"); ## 向数组中添加数据

names_part=(${names[@]:1}); ## 数组提取,表示从下标 1的元素开始的所有元素
print "names_part contains ${names_part[@]}";

names_part=(${names[@]:1:2}); ## 数组提取,表示从下标 1的元素开始,取两个元素
print "names_part contains ${names_part[@]}";

names_part=(${names[@]:0}); ## 数组复制
names_replace=(${names_part[@]/Li/Wang}); ## 数组替换(支持正则表达式),把 Li 替换成  Wang
#names_replace=(${names_part[@]//Li/Wang}); ## 同上
print "names_replace contains ${names_replace[@]}";

## ksh 不支持 行首,行尾,单词边界 正则表达式,下面的方式实现了类似功能
names_part=(${names[@]:0});
names_replace=(${names_part[@]/#S/X}); ## 数组替换,#S 表示S是单词的第一个字母
print "names_replace contains ${names_replace[@]}";

names_part=(${names[@]:0});
names_replace=(${names_part[@]/%i/X}); ## 数组替换,%i 表示 i 是单词的最后一个字母
print "names_replace contains ${names_replace[@]}";

names_part=(${names[@]:0});
names_delete=(${names_part[@]/Z*ang}); ## 数组删除
print "names_delete contains ${names_delete[@]}";

## ksh 不支持 行首,行尾,单词边界 正则表达式,下面的方式实现了类似功能
names_part=(${names[@]:0});
names_delete=(${names_part[@]/#Z*ang}); ## 数组删除,## 匹配开头
print "names_delete contains ${names_delete[@]}";

names_delete=(${names_part[@]/%*n}); ## 数组删除,% 匹配结尾
print "names_delete contains ${names_delete[@]}";

################################# 迭代数组
## for 循环迭代,注意此处有双引号哦,
for e in "${names[@]}";
do
    print $e;
done

## while 循环迭代
i=0;
while [ $i -lt ${#names[@]} ]
do
    print "The ${i}th of names is ${names[$i]}";
    ((i++));
done

################################# 删除数组
unset names[1]; ## 删除下标 1的元素
unset names; ## 删除数组

我们可以通过 ${names[@]} 或 ${names[*]} 得到所有数组元素,但是它们有很大的区别,下面的例子演示了它们的区别。

#!/bin/ksh

################################# 定义数组
names=("abc" "x yz" "1 2 \n3");


################################# 访问数组
length=${#names[*]};
print "The length of array from #names[*] is $length";

length="${#names[*]}";
print "The length of array from \"#names[*]\" is $length";

length=${#names[@]};
print "The length of array from #names[@] is $length";

length="${#names[@]}";
print "The length of array from \"#names[@]\" is $length";


print 'iterating array ${names[*]}';
for e in ${names[*]};
do
    print "#--$e--#";
done

print 'iterating array "${names[*]}"';
for e in "${names[*]}";
do
    print "#--$e--#";
done


print 'iterating array ${names[@]}';
for e in ${names[@]};
do
    print "#--$e--#";
done

print 'iterating array "${names[@]}"';
for e in "${names[@]}";
do
    print "#--$e--#";
done

结果如下:

The length of array from #names[*] is 3
The length of array from "#names[*]" is 3
The length of array from #names[@] is 3
The length of array from "#names[@]" is 3
iterating array ${names[*]}
#--abc--#
#--x--#
#--yz--#
#--1--#
#--2--#
#--
3--#
iterating array "${names[*]}"
#--abc x yz 1 2 
3--#
iterating array ${names[@]}
#--abc--#
#--x--#
#--yz--#
#--1--#
#--2--#
#--
3--#
iterating array "${names[@]}"
#--abc--#
#--x yz--#
#--1 2 
3--#

迭代数组时,只有 “${names[@]}” 能保证正确,注意有双引号的哦。

关联数组(Associative Arrays)

#!/bin/ksh

################################# 定义数组
## 申明关联数组
typeset -A country_code_name_map;

## 赋值方法 1
country_code_name_map[CN]='CHINA';
country_code_name_map[JP]='JAPAN';
country_code_name_map[US]='UNITED STATES';

## 赋值方法 2
country_code_name_map=([CN]='CHINA' [JP]='JAPAN' [US]='UNITED STATES');


################################# 访问数组
print "CN = ${country_code_name_map[CN]}"; ## 取出数组键为 CN 的值

print "country name are ${country_code_name_map[*]}"; ## 取出所有值
print "country name are ${country_code_name_map[@]}"; ## 取出所有值

print "Having ${#country_code_name_map[*]} country names"; ## 数组长度
print "Having  ${#country_code_name_map[@]} country names"; ## 数组长度

print "country code are ${!country_code_name_map[*]}"; ## 取出所有键
print "country code are ${!country_code_name_map[@]}"; ## 取出所有键


################################# 操作数组
country_code_name_map+=([KR]='SOUTH KOREA'); ## 向数组中添加数据

## 数组提取,替换,删除操作和上面一致

################################# 迭代数组
## for 循环迭代
for index in "${!country_code_name_map[@]}";
do
    print "$index = ${country_code_name_map[$index]}";
done


################################# 删除数组
unset country_code_name_map[KR]; ## 删除键为 KR的元素
unset country_code_name_map; ## 删除数组

引用

引用相当于一个别名。

#!/bin/ksh  

typeset name="Shangbo";

## 定义引用变量方法 1
typeset -n name_ref1=name;
print "name_ref1=$name_ref1";

## 定义引用变量方法 2
nameref name_ref2=name;
print "name_ref2=$name_ref2";

## 得到实际变量名
print "name_ref1 reference ${!name_ref1}";

## 删除引用变量
unset -n name_ref1;
unset -n name_ref2;


## 数组的引用
names=("Shang Bo" "Zhang San" "Li Si");
typeset -n names_ref=names;
print "names_ref=${names_ref[@]}";

控制结构

if 语句

#!/bin/ksh

typeset -i x=20;
typeset -i y=3;

if [[ $x -gt $y ]]; then
	print "#** $x >= $y **#"
fi


if [[ $x -gt $y ]]; then
	print "#** $x > $y **#"
else
	print "#** $x <= $y **#"
fi


if [[ $x -gt $y ]]; then
	print "#** $x > $y **#"
elif [[ $x -eq $y ]]; then
	print "#** $x = $y **#"
else
	print "#** $x < $y **#"
fi

case 语句

#!/bin/ksh

typeset opt='a';

case $opt in
	a) print "$opt is a";;
	b) print "$opt is b";;
	c|d) print "$opt is c or d";;
	*) print "Option not support...";;
esac

while 语句

#!/bin/ksh

typeset -i n=0;
typeset -i sum=0;

while [[ $n -lt 11 ]]; do
	(( sum += n++ ));
done
print "sum=$sum";

until 语句

#!/bin/ksh

typeset -i n=0;
typeset -i sum=0;

until [[ $n -gt 10 ]]; do
	(( sum += n++ ));
done
print "sum=$sum";

for 语句

#!/bin/ksh

## 格式1
integer sum=0;
for ((i = 1; i <= 10; i++))
do
    ((sum+=i));
done
print $sum

## 格式2
for foo in $(ls); do
   if [[ -d $foo ]];then
      print "$foo is a directory"
   else
      print "$foo is a file"
   fi
done

select 语句

#!/bin/ksh  


## select 语句应用在交互式程序,显示一个菜单供用户输入
select opt in a b c d; do
	
	## $REPLY 是个内置变量,存储用户输入的数字
	case $REPLY in
		1 ) print "$opt"; break;;
		2 ) print "$opt"; break;;
		3 ) print "$opt"; break;;
		4 ) print "$opt"; break;;
		* ) print "invalid, please select again.";;
	esac

done

循环控制语句

#!/bin/ksh

## break:退出循环  
## continue:执行下一循环  

函数

语法

#!/bin/ksh  

#################### 函数必须先定义后使用

## 定义函数方式 1: ksh 语法
function fun_test1 {
	print "This is function fun_test1.";
}

## 定义函数方式 2: POSIX 语法
fun_test2 (){
	print "This is function fun_test2.";
}

## 参数
function fun_test3 {
	print "Enter function $0"; ## $0 表示函数名
	print "The first parameter is $1"; ## $1 引用第一个参数
	print "The second parameter is $2"; ## $2 引用第二个参数
	print "This function has $## parameters"; ## $## 表示参数的个数
	print "You are calling $0 $*"; ## $* 是个数组,存储所有的参数
	print "You are calling $0 $@"; ## $@ 是个数组,存储所有的参数
}

## return 语句返回代码给调用者
## 0 代表函数执行成功, 其他值代表失败
function equal {
	if [[ -z $1 || -z $2 ]];then  
    	return 1; 
	fi
	
	if [ $1 = $2 ]; then  
	    return 0;
	fi
	
	return 2;
}

## 根据全局变量  max_value 得到函数的返回值
function max {
	if [[ $1 -gt $2 ]]; then  
    	max_value=$1;
	else
		max_value=$2;
	fi
}

## 根据引用得到函数的返回值
function max2 {
	typeset -n r=$3; ## 设置变量 r 引用 $3

	if [[ $1 -gt $2 ]]; then  
    	r=$1;
	else
		r=$2;
	fi
}


## 根据标准输出得到函数的返回值
function min {
	if [[ $1 -lt $2 ]]; then  
    	print $1;
	else
		print $2;
	fi
}

调用

#!/bin/ksh  

#################### Main
## 调用函数
fun_test1;
fun_test2;
fun_test3 a b c d;

equal;
print "Call equal function end with error code $?"; ## $? 表示上个命令返回的代码

typeset -i max_value=0;
max 1 2;
print "the bigger value of 1 and 2 is $max_value";

typeset -i max_value=0;
max2 3 4 max_value;
print "the bigger value of 3 and 4 is $max_value";

## `` 用来捕获函数或命令的标准输入到变量中
smaller=`min 1 2`;
print "the smaller value of 1 and 2 is $smaller";

## $() 用来捕获函数或命令的标准输入到变量中
smaller=$(min 3 4);
print "the smaller value of 3 and 4 is $smaller";

## 删除函数
unset -f fun_test1;
unset -f fun_test2;

注意事项

我们可以从 $* 或 $@ 数组中得到函数的所有参数,但是它们有非常大的区别。

#!/bin/ksh

#################### 函数
function fun_test {
	print 'iterating array $*';  
	typeset -i i=1;
	for p in $*;  
	do  
	    print "The ${i}th parameter is [$p]";  
	    ((i++));  
	done;
	
	
	print 'iterating array "$*"';
	i=1;
	for p in "$*";  
	do  
	    print "The ${i}th parameter is [$p]";  
	    ((i++));  
	done;	
	
	
	print 'iterating array $@';
	i=1;  
	for p in $@;  
	do  
	    print "The ${i}th parameter is [$p]";  
	    ((i++));  
	done;
	
	
	print 'iterating array "$@"';
	i=1;
	for p in "$@";  
	do  
	    print "The ${i}th parameter is [$p]";  
	    ((i++));  
	done;
}

#################### Main
fun_test abc "x yz" "1 2 \n3";

结果:

iterating array $*
The 1th parameter is [abc]
The 2th parameter is [x]
The 3th parameter is [yz]
The 4th parameter is [1]
The 5th parameter is [2]
The 6th parameter is [
3]

iterating array "$*"
The 1th parameter is [abc x yz 1 2 
3]

iterating array $@
The 1th parameter is [abc]
The 2th parameter is [x]
The 3th parameter is [yz]
The 4th parameter is [1]
The 5th parameter is [2]
The 6th parameter is [
3]

iterating array "$@"
The 1th parameter is [abc]
The 2th parameter is [x yz]
The 3th parameter is [1 2 
3]

从上面的结果中可以看出,只有 “$@” 能保证正确,注意,有双引号的哦。

内置函数

函数        返回值
abs	        Absolute value	
hypot       Euclidean distance
acos	    Arc cosine
int         Integer part
sin	        Arc sine
log	        Natural logarithm
atan        Arc tangent
pow         Exponentiation (xy)
atan2       Arc tangent of two variables
sin	        Sine
cos	        Cosine
sinh        Hyperbolic sine
cosh	    Hyperbolic cosine
sqrt        Square root
exp         Exponential (ex)
tan	        Tangent
fmod        Floating-point remainder
tanh        Hyperbolic tangent

命令退出状态

每个 Linux 命令,脚本或函数都有一个退出状态,它用来指示该命令,脚本或函数是否执行成功。0 代表成功,其他值(1-255) 代表失败。

退出状态   描述
1-125    命令执行失败
2        命令使用错误,如参数传递不正确
126      命令不可执行
127      找不到命令
128-255  外部命令执行失败
256	     由于一个信号,命令终止

对于函数来说,我们可以使用 return 语句来返回退出状态,如果一个函数没有 return 语句,默认返回函数中最后执行语句的的退出状态。对于脚本来说,我们可以使用 exit 语句来返回退出状态,如果一个脚本没有 exit 语句,默认返回脚本中最后执行语句的的退出状态。有一点需要特别注意,当脚本中的一条命令执行失败时,整个脚本并不会停止运行,所以对于可能出错的命令,我们最好检查它的退出状态,我们可以通过变量 $? 来得到它的退出状态。下面是一个简单的例子。

#!/bin/ksh  

grep test test.txt > /dev/null;

exit_code=$?;
if [[ $exit_code -ne 0 ]]; then  
    print "command failed."
	exit 1;
fi

事实上,我们可以把命令直接写在 if 语句中,如下:

#!/bin/ksh  

if grep test test.txt > /dev/null; then  
    print "command success.";
else
    print "command failed.";
    exit 1;
fi

如果每条语句都这么检查退出状态,那么你的脚本会很长,其实,我们还可以这么写。

#!/bin/ksh  

## 利用逻辑运算符的短路特性
grep test test.txt > /dev/null && print "command success."
grep test test.txt > /dev/null || print "command failed.";exit 1

向脚本传递参数

方法1

如果你的脚本只需要很少的参数,你可以通过 $1,$2 … $n 直接引用它们。下面是一个简单的例子。

#!/bin/ksh

## $0 表示脚本名
print "The script name is $0";
print "The first parameter is $1";
print "The Second parameter is $2";

你也可以使用 shift 删除前面的参数即可,后面的参数会自动前移,下面是一个简单的例子。

#!/bin/ksh

print "The first parameter is $1";

## shift 删除第一个参数,同时将后面的参数前移
shift;
print "The Second parameter is $1";## 注意此次还是 $1

print "The third parameter is $2";
print "The fourth parameter is $3";

## shift 删除前三个参数,同时将后面的参数前移
shift 3;
print "The fifth parameter is $1";## 注意此次还是 $1

方法2

事实上,ksh 会自动将所有的参数放到数组 $@ 和 $* 数组中,你可以迭代它来得到所有的参数。下面是一个简单的例子

#!/bin/ksh

#-------------- $## 表示参数的数量 ---------------#
print "This script has $## parameters.";

#-------------- 迭代数组 $@ ---------------#
typeset -i i=1;
print 'iterating array $@';
for p in $@;
do
	print "The ${i}th parameter is [$p]";
	((i++));
done;


#-------------- 迭代数组 $* ---------------#
i=0;
print 'iterating array $*';
for p in $*;
do
	print "The ${i}th parameter is [$p]";
	((i++));
done;

ksh 为什么会将参数放在两个数组中( @ , @, @*),它们有什么区别呢?下面的例子演示了它们之间的区别。

#!/bin/ksh

#-------------- 迭代数组 $*---------------#
print 'iterating array $*';
for p in $*;
do
	print "#--[$p]--#";
done;


#-------------- 迭代数组 "$*",注意数组用双引号括起来 ---------------#
print 'iterating array "$*"';
for p in "$*";
do
	print "#--[$p]--#";
done;


#-------------- 迭代数组 $@ ---------------#
print 'iterating array $@';
for p in $@;
do
	print "#--[$p]--#";
done;

#-------------- 迭代数组 "$@",注意数组用双引号括起来 ---------------#
print 'iterating array "$@"';
for p in "$@";
do
	print "#--[$p]--#";
done;

结果如下:

iterating array $*
#--[abc]--#
#--[x]--#
#--[yz]--#
#--[1]--#
#--[2
3]--#
iterating array "$*"
#--[abc x yz 1 2
3]--#
iterating array $@
#--[abc]--#
#--[x]--#
#--[yz]--#
#--[1]--#
#--[2
3]--#
iterating array "$@"
#--[abc]--#
#--[x yz]--#
#--[1 2
3]--#

从上面的结果可以看到,只有"$@"能保证正确,注意有双引号哦。

方法3

如果你想像 Linux 命令那样传递参数,你需要用到函数 getopts。

#!/bin/ksh

## OPTIND 表示当前参数的索引
print "Current parameter index is $OPTIND";

## 调用此脚本的方式: ./test.ksh -a -b 'test' -c 10 eee ff g
#
## getopts 函数有两个参数
#
## 第一个参数(:ab:c#)是该脚本支持的选项
## 最前面的冒号表示  getopts 抑制错误消息,由脚本自己提供错误处理
## b 后的冒号表示改选项需要一个字符参数 (-b 'test')
## c 后的井号表示改选项需要一个数字参数 (-c 10)
#
## 第二个参数  optname 是一个变量名,接收函数返回的选项

while getopts ":ab:c#" optname
do
	case "$optname" in
		"a")
			print "Option $optname is specified"
			;;
		"b")
			## $OPTARG 保存选项后面的参数值,此例是 test
			print "Option $optname has value $OPTARG"
			;;
		"c")
			print "Option $optname has value $OPTARG"
			;;
		"?") ## ? 表示发现不能识别的选项
			print "Unknown option $OPTARG"
			exit -1
			;;
		":") ## : 表示发现某个选项需要值,但是找不到这个值, 此时  OPTARG 包含丢失参数的选项
			print "No argument value for option $OPTARG"
			exit -1
			;;
		*)
       print "Unknown error while processing options"
       exit -1
       ;;
    esac
    print "Current parameter index is $OPTIND";
done

## 选项后面的参数 (eee ff g)
argstart=$OPTIND;
for p in "${@:$argstart}"
do
	print "[$p]";
done

I/O

ksh 支持如下 I/O。

重定向          描述
> file        标准输出到文件,文件存在则替换
>> file       标准输出到文件,文件存在则添加到末尾
< file        从文件到标准输入
<> file       以读写模式打开文件
cmd1 | cmd2   管道; 把 cmd1 的标准输出作为 cmd2 的标准输入
>| file       Force standard output to file even if noclobber is set
<< label      Here-document
<<- label     Here-document variant
<<< label     Here-string
n> file       把文件描述符 n 输出到文件(1是标准输出,2是标准错误输出)
n< file       输入文件描述符 n (0是标准输入)
<&n           从文件描述符 n重复标准输入
>&n           重复标准输出到文件描述符 n
<&n-          把文件描述符 n作为标准输入
>&n-          把文件描述符 n作为标准输出
<&-           关闭标准输入
>&-           关闭标准输出
|&            Background process with I/O from parent shell
n<&p          Move input from coprocess to file descriptor n
n>&p          Move output to coprocess to file descriptor n

大家对 > file, >> file, < file 和 cmd1 | cmd2 应该都很熟悉, 只要懂一点 Linux 的人不可能没用过。 n> file 和 >&n 看上去挺陌生,其实你肯定也用过,看看下面的命令吧,是不是很熟悉。

cmd > t.log 2>&1

什么是 Here-document (<< label,<<- label) 呢?你肯定也用过,只是不知道它的名字而已。看看下面的代码吧。

#!/bin/ksh

user="wave0409@163.com";

##  << label
mail $user << EOF
Hi $user,

This is a test mail, please ignore.

Regards
EOF


##  <<- label 会忽略前面的 TAB,使代码可读性更好
mail $user << EOF
		Hi $user,
		
		This is a test mail, please ignore.
		
		Regards
		EOF

什么是 Here-string 呢?看看下面的代码吧。

#!/bin/ksh

user="wave0409@163.com";
text="this is a test mail.";

## 使用管道
print $text | mail $user;

##  <<< label
mail $user <<< $text;

通常,Linux 命令只接受一个输入和一个输出,但是通过下面的方式,我们可以接受多个输入和多个输出。

cmd  <(input) <(input)
cmd  >(output) >(output)

下面是一个简单的例子。

#!/bin/ksh  

## 将原始数据test.txt,1)排序后输出test.txt.sort 2) 取第二列输出test.txt.id 3) 保存原始数据 test.txt.raw
cat test.txt | tee >(sort | uniq > test.txt.sort) >(cut -d, -f2 test.txt > test.txt.id) > test.txt.raw

格式化输出

简单示例

几乎所有的语言都支持 printf 函数,ksh 也不例外。下面我们来看一个简单的例子。

#!/bin/ksh

printf "printf example:%,30.6f" 9876543210.0123456789;

结果如下:

printf example:          9,876,543,210.012346

%,30.6f 被称为格式符(format specifier), 格式符由以下几部分组成:

%[flags][width][.precision]conversion  
%  ,      30      .6         f  

注意事项

  • %是必须的, 任何格式符都由百分号开始.
  • flags 是可选的, 详见下表.
  • width 是可选的, 表示输出的宽度.
  • precision 可选的, precision 依赖于 conversion, 详见下表.
  • conversion 是必须的, 表示如何格式化参数, 详见下表.

转换符(conversion)

ksh 支持如下转换符(conversion)。

转换符           描述
 d               十进制整数,也可进制转换
 i               十进制整数
 u               无符号十进制整数 
 e               浮点数科学计数法
 E               浮点数科学计数法
 f               浮点数
 g               %e 或 %f, 取决于哪个更短, 删除尾部0
 G               %E 或 %f, 取决于哪个更短, 删除尾部0
 o               无符号八进制整数
 x               无符号十六进制整数(a-f for 10 to 15)
 X               无符号十六进制整数(A-F for 10 to 15)
 c               ASCII 字符 (打印第一个字符)
 %               %
 s               字符串
 b                %s,支持更多的转义字符
 H                %s,转成 HTML 字符,如:空格转成  
 P                %s,把 egrep 风格的正则表达式转成 ksh 风格
 R                %s,把 ksh 风格的正则表达式转成 egrep 风格
 q                %s,打印成 $'...' 风格
 n               到字符串的长度
 (date format)T  格式化日期

日期和时间转换符

转换符(Conversion)	描述(Description)
Y	                4位数字的年(前面补0)
m	                月,01-12
d	                日,01-31
H	                小时,00-23
M	                分钟,00-59
S	                秒,00-60
I	                小时,01-12
N	                纳秒,000000000 - 999999999
P	                本地敏感, PM or AM
p	                本地敏感,pm or am
z	                时区偏移量, 如 +0800
Z	                时区
s	                从格林威治时间1970-01-01 00:00:00起的秒数
B	                月的完整拼写
b/h	                月的缩写
A	                星期的完整拼写
a	                星期的缩写
y	                年的后两位数字(前面补0)
C	                年的前两位数字(前面补0)
j	                一年的第几天,001-366
e	                日,1-31
R	                24小时时间,如 18:05
T	                24小时时间,如 18:05:19
r	                12小时时间, 如 06:05:19 pm
D	                美国格式的日期(月/日/年),如 02/09/2004
F	                ISO 8601 日期, 如 2004-02-09
c	                完整的日期和时间,如 Tue Oct  6 09:15:27 2015
k	                完整的日期和时间,如 Tue Oct  6 09:18:22 EDT 2015
l                   完整的日期和时间,如 Oct  6 09:19
L                   完整的日期和时间,如  Tue Oct  6 09:20:17 EDT 2015

标志(flag)

ksh 支持如下标志(flag)

标志         描述               举例
-           左对齐             |3333.33 |
空格         在正数之前添加空格    | 3333.33|,|-3333.33|
+           打印正负数符号       |+3333.33|,|-3333.33|
0           数字前面补0         |003333.33|
,           添加千分位          |3,333.33|
#(对于%o)    添加前缀0           |0515|
#(对于%x)    添加前缀0x	      |0x1bc|
#(对于%X)    添加前缀0X	      |0X1bc|
#(对于%e)    添加小数点          |1.000000e+01|
#(对于%E)    添加小数点          |1.000000E+01|
#(对于%f)    添加小数点          | 10.000000|
#(对于%g)    不删除尾部0         |10.4000|
#(对于%G)    不删除尾部0         |10.4000|

精度(precision)

ksh 精度(precision)的意义。

转换符                 精度意义
%d,%i,%o,%u,%x,%X    最少数字位数,如果数字位数少于精度,添加前缀0
%e, %E               最少数字位数,如果数字位数少于精度,添加后缀0
%f                   小数的位数
%g, %G               最多数字位数
%s                   字符位数

例子

#!/bin/ksh

## %b 同 %s,支持更多的转义字符
printf "%b\n" 'hello\nworld';

## %H 同 %s,转成 HTML 字符,如:空格转成  
printf "%H\n" "Here are real < and > characters";

## %P 同 %s,把 egrep 风格的正则表达式转成 ksh 风格
printf "%P\n" '(.*\.o|.*\.obj|core)+';

## %R 同 %s,把 ksh 风格的正则表达式转成 egrep 风格
printf "%R\n" '+(*.o|*.c)';

## %q 同 %s,打印成 $'...' 风格
printf "print %q\n" "a string with ' and \" in it"

## %d,进制转换
printf '42 is %.3.5d in base 5\n' 42

## %n 得到字符串的长度
printf "hello, world\n%n" msglen;
print $msglen;

## %(date format)T, 格式化日期
printf "%(It is now %Y-%m-%d %H:%M:%S)T\n" "$(date)"

动态命令

有时候我们需要动态生成一些命令,然后执行。下面是一个简单的例子。

#!/bin/ksh

cmd="ls | more";
$cmd;

如果你执行上面的脚本,你会收到下面的错误消息,原因是 ksh 把 | 理解成了一个文件名。

ls: cannot access |: No such file or directory

遇到这种情况该如何处理呢?呵呵,so easy,你只需要在命令前加上 eval 即可,如下。

#!/bin/ksh

list="ls | more";
eval $list;

多进程

作业控制

当我们在 ksh 中执行一条命令时,在命令结束之前,我们能做的只有等待,如果命令需要运行很长时间,在这段时间内你还想干点别的,你可以通过下面的方式运行命令。

#!/bin/ksh

## 在命令的末尾加上 & 表示在后台执行该命令
ls > /dev/null &

当你按回车后,你马上会看到如下输出,1 表示作业号(Job Number),3106 表示进程号(Process ID)。

[1] 3106

命令执行完后,会有如下输出。

[1]+  Done                    ls --color=auto > /dev/null

如果命令执行错误,你会看到如下输出,2 表示错误代码。

[1]+  Exit 2                  ls --color=auto dd /dev/null

你可能想,能不能把一个正在运行的命令放在后台执行呢?答案是肯定的,你需要两步。

第一步,按 CTRL-Z 暂停命令,你会得到如下的输出。

[1]+  Stopped                 vi test.txt

第二步,执行下面的命令把它放在后台执行。

bg %1

上面的 %1 表示作业号为 1 的作业。我们还可以通过下面的方式引用进程或作业。

引用        进程
N           进程号 N
-N          进程组号 N
%N          作业号 N
%string	    以 string 开头的命令
%?string    包含 string 的命令
%+或%%      最后被调用的命令
%-          倒数第二被调用的命令

如果你想查看当前有哪些进程在后台执行,你可以运行 jobs 命令,如果你想把某个后台命令放在前台执行,试一试 fg %N 吧。
通常,当你退出登录时,你运行的所有命令,不管前台还是后台都会被终止,如果你想让某个命令在你退出登录时继续执行,试一试 disown %N 吧。当然你也可以采用如下的方式运行命令,这样即使你退出登录,也能保证不会被终止。

nohup ls > /dev/null &

进程管理

很多人认为 kill 命令就是用来杀掉进程的,其实它是用来给进程发送信号(Signal)的,我们可以给进程发送哪些信号呢?试一试下面的命令吧。

kill -l

结果如下:
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

下面是一些简单的例子。

## 3106 是进程号,我们也可以通过作业号,命令名引用进程
kill 3106 ## 发送 TERM 信号终止进程
kill -15 3106 ## 同上
kill -s TERM 3106 ## 同上

kill -s INT 3106 ## 发送 INT 信号中断进程,同 CTRL-C
kill -s QUIT 3106 ## 发送 QUIT 信号退出进程
kill -s KILL 3106 ## 发送 KILL 信号杀死进程

上面提到的 jobs 命令只能查询到当前 shell 启动的进程,如果你想查看所有的进程,你可以使用 ps 命令。下面是一个简单的例子。

ps -ef | grep 'vi test.txt' | grep -v grep

多进程

假设某个目录下有好多 SQL 文件,现在让你把它们都运行一遍,你可以采用如下的脚本。

#!/bin/ksh  

## 扫描所有的 SQL 语句并运行
for sql in $(ls *.sql)
do
	runSQL ${sql};
done
print "done";

由于某些 SQL 需要运行很长时间,导致这个脚本很慢,其实,你可以并发执行所有的 SQL 文件,如下。

#!/bin/ksh

function clean {
	print "received interrupt signal.";
	## disconnect db and clean tmp file etc
	exit;
}

## trap 表示如果收到 INT,TERM 或  QUIT 信号就运行函数 clean
trap 'clean' INT TERM QUIT

## 扫描所有的 SQL 语句并运行
for sql in $(ls *.sql)
do
	## 在后台运行 SQL 语句
	runSQL ${sql} &;
done

## wait 命令等待所有后台命令执行完毕
wait;
print "done";

控制键

如果你想结束一个正在运行的命令怎么办?试一试 CTRL-C 吧。 CTRL-C 是一个控制键,如何查看 Shell 都支持哪些控制键呢?试一试下面的命令吧。

stty -a
控制键                 stty名    描述
CTRL-C	              intr     终止当前命令
CTRL-\ or CTRL-|      quit	   终止当前命令
CTRL-Z                susp     暂停当前命令
DEL or CTRL-?         erase    删除最后一个字符
BACKSPACE or CTRL-H	  erase    删除最后一个字符
CTRL-U                kill     删除整行命令
CTRL-D                eof      终止输入
CTRL-S                stop     暂停输出
CTRL-Q                start    恢复输出
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值