第2章 Shell编程
2.1 Bash脚本的建立与运行
Shell命令行
;
分隔命令\
表示换行补充
Shell程序是指放在一个文件中的一系列Linux命令和实用程序,执行时操作系统逐个解释和执行
Bash脚本的建立
echo "Mr.$USER, today is:"
echo &date "+%B%d%A"
echo "Wish you a lucky day!"
# 改变权限 for 可执行
chmod +x shell21
# 执行程序
./shell21
bash shell21
2.2 Shell程序的位置参数与变量
位置参数
位置参数
- 系统提供,将参数列表看做一个数组,访问:
$N
$0
为脚本文件的名字
cho $0
echo $1
echo $* # 所有参数
echo $@ # 所有参数
echo $# # 参数个数
echo $$ # shell脚本进程ID号
echo $? # 最近一次命令退出状态
echo $! # 最后一次后台的ID号
- 执行
$ bash 221 arg1 arg2
221
arg1
arg1 arg2
arg1 arg2
2
44286
0
- 参数超过9个,则
shift [N]
- 表示将参数左移
N
个位置,然后继续使用数组下标来访问
- 表示将参数左移
$ cat 24
echo $1
shift 2
echo $1
$ bash 24 1 2 3 4
1
3
设置位置参数的值
base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat 25
#! /bin/bash
filename=$1
set $(ls -il $filename) # 将后面命令的输出设置为参数列表
ls -il $filename
inode=$1
right=$2
size=$6
echo "inode=\$1=$inode"
echo "right=\$2=$right"
echo "size=\$6=$size"
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ bash 25 main.c
2361026 -rw-rw-r-- 1 cola cola 0 2月 3 20:50 main.c
inode=$1=2361026
right=$2=-rw-rw-r--
size=$6=0
环境变量与用户定义变量
指在在执行Shell脚本时的变量来源
- 环境变量
$HOME # 当前用户主目录
$PATH # 搜索命令的目录
$PS1 # ?
$PS2
$IFS # 内部域分隔符
- 用户变量: 数字、字母下划线,且大小写敏感
变量申明和赋值
申明变量
- 变量默认是空字符串
- 通过设置
options
来设定其类型
命令格式
declare [options] [name[=value]]
typeset [options] [name[=value]]
# options
-a # array
-f # function
-i # integer
-r # read only
-x # 全局变量,可以被子进程访问
变量赋值
variable=value
- 类型不同不能赋值
例如
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat 223
declare -i age=20
declare -rx OS=LINUX
var1=$OS
var2="abcd"
declare -i var3=10
echo $age
echo $OS
echo $var1
echo $var3
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ bash 223
20
LINUX
LINUX
10
- 变量申明及赋值
- 默认赋值为字符串
变量引用和单双引号使用
引用
$var
访问值var=value
可以用于修改变量- 第一次使用则会自动创建
单、双引号、反斜线的使用
$ declare -i age=20
$ echo $age
20
$ echo 'age==$age'
age==$age
$ echo "age==$age"
age==20
$ echo "age==\$age"
age==$age
''
: 原封不动字符串""
: 对**$ \ `**作出解释
命令替换
两种命令替换方式
$(command)
$ echo "Infomation of 223: $(ls -l 223)"
Infomation of 223: -rw-rw-r-- 1 cola cola 120 2月 4 17:28 223
- 反引号会将其输出替换为命令的输出结果 -> 命令替换
$ ls -l 223
-rw-rw-r-- 1 cola cola 120 2月 4 17:28 223
$ declare info=`ls -l 223`
$ echo $info
-rw-rw-r-- 1 cola cola 120 2月 4 17:28 223
变量的输入
- 从标注输入中输入一个变量
- 换行结束
read [options] variable-list
# 常用选项如下
-a # 词读入name数组中
-e # 一整行读入一个变量,其余位NULL
-n # echo输出命令字符后,光标任在同一行
-p prompt # 从终端读入数据则显示prompt字符串
-
注意
- 赋值过多则剩余的全给最后一个变量
- 赋值过少则,多余变量接受NULL
-
以下Shell脚本,列出指定文件夹的文件信息,然后再回到工作路径
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat 29
workspace=$PWD
echo "Enter direction path:"
read dir_name
cd $dir_name
ls -l
cd $PWD
pwd
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./29
Enter direction path:
../code1
总用量 32
-rw-rw-r-- 1 cola cola 64 2月 3 20:34 221
-rw-rw-r-- 1 cola cola 120 2月 4 17:28 223
-rw-rw-r-- 1 cola cola 24 2月 3 20:42 24
-rw-rw-r-- 1 cola cola 212 2月 3 20:57 25
-rwxrwxr-x 1 cola cola 89 2月 4 22:43 29
-rw-rw-r-- 1 cola cola 60 2月 3 20:25 cola22.cola
drwxrwxr-x 2 cola cola 4096 2月 3 20:25 kk
-rw-rw-r-- 1 cola cola 0 2月 3 20:50 main.c
-rwxrwxr-x 1 cola cola 77 2月 3 20:10 shell21
/home/cola/cola_study/LinuxProgramming/code1
2.3 控制结构语句
bool运算
test [expression]
[ [expression] ] # 外面的[]即表示 test
字符串比较
- 以下均返回
true
abcd = abcd
bcd != abcd
-n "cajd" # 字符串不为空
-z "" # 字符串为空
算数比较
exp1 -eq exp2
# more 双元
-ne
-gt
-ge
-lt
-le
# 一元
!exp
文件测试
-d dir
-e file_exist
-f filename
-r filename # 可读
-s filename # 文件长度不为0
-w filename # 文件可写
-x filename # 文件可执行
顺序结构的语句
- 略
if-then-elif-else-fi
语句
- 语句规则总结如下
if exp1
then
...
elif exp2
then
...
elif exp3
then
...
else
...
fi
- 使用案例: 删除某个文件,删除前做以判断,且是将文件压缩后送入回收站
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat 211.sh
if test $# -eq 0
then
echo "Please enter specify file!"
else
gzip $1 # 对文件进行压缩
mv $1.gz $HOME/dustbin # 移动到回收站
echo "Moving right!"
fi
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./211.sh 25
Moving right!
- 案例:输入文件则显示文件内容,文件夹则显示文件夹下的内容
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat 212.sh
read file_or_dir
if [ -d $file_or_dir ]
then
ls -l $file_or_dir
elif [ -f $file_or_dir ]
then
cat $file_or_dir
else
echo "Input error."
fi
for语句
- 和
python
里面的类似
for variable [in argument-list]
do
command-list
done
- 使用
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
for filename in $*
do
echo $filename
done
echo "Phase 2"
for item in abc deg g
do
echo $item
done
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh a b c d e
a
b
c
d
e
Phase 2
abc
deg
g
- 使用其他分隔符IFS(Internal Field Separator)
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
data="a, b, c, d"
IFS=", "
for item in $data
do
echo $item
done
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
a
b
c
d
- 列出某个文件夹下所有文件
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
trash_path="$HOME/.local/share/Trash/files/"
for filename in $(ls $trash_path)
do
echo $filename
done
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
baboon0.png
baboon1.png
baboon.2.png
baboon2.png
baboon3.png
baboon.png
cola_1.c
- 列出文件夹下所有模式的文件
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
for filename in $(ls *.sh)
do
echo $filename
done
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
211.sh
212.sh
test.sh
-
计算数列前
n
项和-
todo
-
echo "N:" declare -i n declare -i num read n total=0.000 an=1.000 for ( (num=1; num<=$n; num++) ); do an=`echo "scale=3; 1.000/$num" | bc` total=`echo "scale=3; $total+%an" | bc` done echo $total
-
上面为有bug的代码
-
while语句
while expression
do
command-list
done
- 输入直到条件成立
read input_sec
while [ $input_sec != "cola" ]
do
echo "error!"
read input_sec
done
echo "Input right"
- 指定循环
n
次
read input
declare -i times=$input
declare -i time=0
while test $time -lt $times
do
read input
echo "Input=$input"
time=$time+1
done
utile语句
until expression
do
command-list
done
expression
一直为假则执行,直到其为真
case语句
- 同嵌套的
if
语句类似的多路跳转功能 - 替代条嵌套多层的
if
语句
case variable in
pattern1 ) ...
;;
pattern2 ) ...
;;
pattern3 ) ...
;;
pattern ) ...
;;
esac
2.4 其他几个常用语句
break/continue
- 同c
exit
- 功能: 退出脚本
- 不同的退出码代表不同的含义
exit n
# 退出码解释
n 含义
0 成功
126 文件不可执行
127 命令未找到
>=128 出现一个信号
printf
- 和C/C++输出类似
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ age=20
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ printf "name is %s\n%s\n" "Cola Cheng" "age=$age"
name is Cola Cheng
age=20
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ printf "%d %f %lf \n" 2 3.3 3.3
2 3.300000 3.300000
2.5 数值处理
- 变量值军事字符串格式存储
- 要进行算数运算或者逻辑运算,得先将字符串转为整数,得到结果再转回字符串
- 算数运算符和C/C++中相同
let命令
let expression-list
- 感觉上,就像是有一个简单的符号计算器
- 内部变量不需要使用
$
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
z=4
let x=3 y=4
let t=x*y*z "t2=x**y"
echo $t $t2
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
48 81
$((expression))$
扩展
- 运算结果直接替换
- 用于命令行的参数替换
- Shell必须将字符串转为整数 if 使用的变量不是正的整数(a=30是真的整数,a=2.2不是)
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
echo "Inpute you age:"
read age
echo Next $((100-age)) years.
echo $((age*10))
content=$(( $(wc -l < test.sh)*2+1 ))
echo $content
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
Inpute you age:
21
Next 79 years.
210
15
expr 命令
- 将参数作为表达式求值
expr args
# 常用
x = `expr $x+1`
- 使用
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
a1=4
a1=$( expr $a1 + 1 )
echo $a1
a1=$( expr $a1 + 3 \* 3)
echo $a1
echo $( expr $a1 / 4 )
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
5
14
3
- 注意:
- 表达式中所有符号必须分割开,不然会被解析为字符串!
- 乘法需要使用
\*
2.6 数组
数组基本操作
- 定义、下标访问、计算长度、删除元素
# array define
arr=(ab cd ef)
# indicate array
echo ${arr[1]}
# length of array
echo ${#arr} # len of arr[0] (byte)
echo ${#arr[0]} # same
echo ${#arr[*]} # 数组元素个数
# delete array
unset arr[0]
unset arr
数组子串操作
子串访问
a=(zero one two three four five)
echo ${a[@]:1:3}
echo ${a[@]:2}
echo ${a[@]::3}
删除子串
# 删除子串
echo ${a[@]#f*r} # 删除左边开始最短匹配
echo ${a[@]#f*r} # 删除左边开始最长匹配
echo ${a[@]%f*r} # 删除右边开始最短匹配
echo ${a[@]%%f*r} # 删除右边开始最短匹配
子串替换
- 略
2.7 函数
function_name() {
command-list
}
参数传递&局部变量定义&返回值
- 变量位置参数
$*、$@
等将会替换为函数的参数(函数局部有效) local
关键词可以在Shell函数中声明局部变量- 同名变量则局部覆盖全局
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ cat test.sh
func() {
# 使用位置参数
for item in $*
do
echo $item
done
# 定义局部变量
local var=abcd
echo $var
# 返回值
return 1
}
if func cola ysc
then
echo "func return true"
fi
(base) cola@cola-CM:~/cola_study/LinuxProgramming/code1$ ./test.sh
cola
ysc
abcd