Shell编程

Shell编程

shell脚本编程

构建基本脚本

注释格式

1
2
3
4
5
6
7
8
#!/bin/sh

# FILENAME: test_shell
# AUTHOR: Javy
# Email: xujavy@gmail.com
# PURPOSE: Demonstration of comment style
# HISTORY: 1 May, 2018 Created
# 5 May, 2018 Modified to show mods

显示消息

1
echo This is a test

说明:

  • -n:输出在同一行

使用变量

1. 环境变量
  • set 显示所有的当前环境变量列表

例如:

1
2
3
4
5
#!bin/bash
# display user information from the system.
echo "User info for userid: $USER"
echo UID: $UID
echo HOME: $HOME
2. 用户变量
3. 命令替换
  • 反引号字符( `)

  • $()格式

1
2
#!bin/bash
testing=$(date)

重定向输入和输出

1. 输出重定向

command > outputfile

2. 输入重定向

command < outputfile

管道

执行数学运算

1. expr命令
1
expr 1 + 5
2. 使用方括号

$[ operation ]

3. 浮点解决方案
  • bc的基本用法
1
2
3
bc -q

quit
2. 在脚本中使用bc

variable=$(echo "options; expression" | bc)

说明:

options:设置变量,允许多个变量可以用分号隔开。

expression:定义bc执行的数学表达式。

variable=$(bc << EOF options statements expression EOF )

退出脚本

1. 查看退出状态码

$?可查看退出状态

说明:

状态码 描述
0 命令成功结束
1 一般性未知错误
2 不适合的shell执行命令
126 命令不可执行
127 没找到命令
128 无效的退出参数
128+x 与Linux信息x相关的严重错误
130 通过Ctrl+C终止的命令
255 正常范围之外的退出状态码
2. exit命令

可以指定退出码exit num,num表示0~255之间的数,如果大于将以取模的形式返回。

使用结构化命令

使用if-then语句

格式:

1
2
3
if command then
commands
fi

说明:

if后面的command是一个命令,如果命令退出代码是0,then部分就会被允许,如果是其他码then部分不会被执行。

使用if-then-else语句

格式:

1
2
3
4
5
if command then
commands
else
commands
fi

嵌套if

test命令

test condition

1
2
3
if test condition then
commands
fi

也可以写为:

1
2
3
if [ condition ] then
commands
fi

test命令可以判断的三类条件:

  • 数值比较

  • 字符串比较

  • 文件比较

1. 数值比较
比较 描述 比较命令说明
n1 -eq n2 n1是否与n2相等 -equal
n1 -ge n2 n1是否大于或等于n2 -(greater and equal)
n1 -gt n2 n1是否大于n2 -(greater than)
n1 -le n2 n1是否小于或等于n2 -(less and equal)
n1 -lt n2 n1是否小于n2 -(less than)
n1 -ne n2 n1是否不等于n2 -(not equal)
2. 字符串比较
比较 描述
str1 = str2 str1是否与str2相同
str1 != str2 str1是否与str2不同
str1 < str2 str1是否比str2小
str1 > str2 str1是否比str2大
-n str1 str1的长度是否非0
-z str1 str1的长度是否为0

注: 在使用<>是需要进行转义,就想这样\<\>

3. 文件比较
比较 描述
-d file file是否存在并是一个目录
-e file file是否存在
-f file file是否存在并是一个文件
-r file file是否存在并可读
-s file file是否存在并非空
-w file file是否存在并可写
-x file file是否存在并可执行
-o file file是否存在并属当前用户所有
-G file file是否存在并默认与当前用户相同
file1 -nt file2 file1是否比file2新
file1 -ot file2 file1是否比file2旧

复合条件测试

  • [ condition1 ] && [ condition2 ]

  • [ condition1 ] || [ condition2 ]

if-then的高级特性

  • 用于数学表达式的双括号

  • 用于高级字符串处理功能的双方括号

1. 使用双括号

格式:

(( expression ))

表达式参数符号说明:

符号 描述
val++ 后增
val– 后减
++val 先增
–val 先减
! 逻辑求反
~ 位求反
** 幂运算
<< 左位移
>> 右位移
& 位布尔和
&#124 位布尔或
&& 逻辑和
&#124&#124 逻辑或
2. 使用双方括号

[[ expression ]]

case命令

格式:

1
2
3
4
5
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac

更多的结构化命令

for命令

格式:

1
2
3
4
for var in list
do
commands
done

C语言风格的for命令

格式:

for (( variable assignment ; condition ; iteration process ))

使用多个变量:

1
2
3
for (( a=1, b=10; a <= 10; a++, b-- )); do
#statements
done

while命令

格式:

1
2
3
4
while [ command ]
do
other commands
done

until命令

格式:

1
2
3
4
until [ command ]
do
other commands
done

嵌套循环

循环处理文件数据

控制循环

1. break命令

跳出外部循环:break n (默认n=1)

2. continue命令

处理循环的输出

1
2
3
for (( i = 0; i < 10; i++ )); do
#statements
done > outputfile.txt

最后的结果使用定向输出:>

处理用户输入

命令行参数

1. 读取参数

位置参数变量是标准的数字:$0是程序名,$1是第一个参数,$2是第二个参数,依次类推直到第九个参数$9。

2. 抓取所有的数据

$*$@可以抓取命令行上的所有参数。但是$*是当作一个参数执行,而$@是对每个参数进行处理

3. 移动变量

shift 2:移动两个位置

4. 处理选项

分离参数和选项(--

使用getopt命令:getopt optstring parameters,在脚本中使用格式:set – $(getopt -q ab:cd “$@”)

使用更高级的getopts:getopt optstring variable

4. 获得用户输入

read

1
2
3
echo -n "Enter your name: "
read name
echo "Hello $name, welcome to my program. "

read -p

1
2
3
read -p "Enter your age: " age
days=$[ $age * 365 ]
echo "That makes you over $days days old! "
2. 超时

read -t

1
2
3
4
5
6
7
if read -t 5 -p "Please Enter your name: " name
then
echo "Hello $name, welcome to my program. "
else
echo
echo "Sorry, too slow!"
fi

read -n1

1
2
3
4
5
6
7
8
9
read -n1 -p "Do you want to continue [Y/N]?: " answer
case $answer in
Y | y) echo
echo "fine, continue on...";;
N | n) echo
echo "Ok, goodbye"
exit;;
esac
echo "This is the end of the script"
3. 隐藏方式读取

read -s

1
2
3
read -s "Enter your password: " pass
echo
echo "Is your password really $pass? "
4. 从文件中读取
1
2
3
4
5
6
7
Count=1
cat test | while read line
do
echo "Line $Count: $Line"
Count=$[ $Count + 1 ]
done
echo "Finished processing the file"

呈现数据

理解输入和输出

1. 标准文件描述符
文件描述符 缩写 描述
0 STDIN 标准输入
1 STDOUT 标准输出
2 STDERR 标准错误
2. 重定向错误

ls -al test 2> test1 1> test2

ls -al test &>test1

在脚本中重定向输出

1. 临时重定向
2. 永久重定向
1
2
3
4
exec 1>testout

echo "...."
echo "......."

在脚本中重定向输入

exec 0< testfile

创建自己的重定向

1. 关闭文件描述符

exec 3>&-

列出打的开文件描述符

lsof

记录消息

tee filename 默认会覆盖

tee -a filename 实现追加

实例

1
2
3
4
5
6
7
8
9
10
11
#!bin/bash
# read file and create INSERT statements for MySQL

outputfile='member.sql'
IFS=','
while read lname fname address city state zip
do
cat \>> $outputfile \<< EOF
INSEART INTO members (lname, fname, address, city, state, zip) VALUES ('$lname', '$fname', '$address', '$city', '$state', '$zip');
EOF
done < S{1}

控制脚本

处理信号

1. 重温Linux信号
信号 描述
1 SIGHUP 挂起进程
2 SIGINT 终止进程
3 SIGQUIT 停止进程
9 SIGKILL 无条件终止进程
15 SIGTRERM 尽可能终止进程
17 SIGSTOP 无条件停止进程但不是终止进程
18 SIGTSTP 停止或暂停进程,但不终止进程
19 SIGCONT 继续运行停止的进程
2. 生成信号
  • 中断进程

Ctrl + C

  • 暂停进程

Ctrl + Z

3. 捕获信号

格式:

tarp commands signals

4. 捕获脚本退出

tarp commands signals EXIT

5. 修改或移除捕获

以后台模式运行脚本

1. 以后台运行脚本

./test.sh &

2. 运行多个后台作业

在非控制台下运行脚本

格式:

nohup ./test.sh &

作业控制

1. 查看作业

jobs

参数说明:
| 参数 | 描述 |
| — | —- |
| -l | 列出进程的PID以及作业号 |
| -n | 只列出上次shell发出的通知后改变了状态的作业 |
| -p | 只列出作业的PID |
| -r | 只列出运行中的作业 |
| -s | 只列出已停止的作业 |

2. 重启停止的作业

后台模式运行:bg id

前台模式运行:fg id

调整谦让度

1. nice命令

nice -n:指定新的优先级级别

2. renice命令

renice -n 10 -p 5055

定时运行作业

1. 用at命令来计划执行作业
  1. at命令的格式

格式:

at [ -f filename ] time

at -f test.sh now

  1. 列出等待的作业

atq可以查看系统中等待的作业

  1. 删除作业

arrm删除等待的作业

2. 安排需要定期执行的脚本
  1. cron时间表

格式:

min hour dayofmonth month dayofweek command

  1. 构建cron时间表

crontb -l:列出时间表

  1. 浏览cron目录

包括:hourly、daily、monthly、weekly

ls /etc/cron.*ly

  1. anacron程序

格式:

period delay identifier command

高级shell脚本编程

创建函数

基本的脚本函数

1. 创建函数

function name {
commands
}

name() {
commands
}

2. 使用函数

返回值

  • 默认退出状态码

$?

  • 使用return命令

注意: 函数一结束就取返回值;退出状态码必须是0~255。

  • 使用函数输出

在函数中使用变量

局部变量:local temp

数组变量和函数

图形化桌面环境中的脚本编程

初识sed和gawk

文本处理

1. sed编辑器

sed:stream editor

说明:

  1. 一次从输入中读取一行数据

  2. 根据所提供的编辑器命令匹配数据

  3. 按照命令修改流中的数据

  4. 将新的数据输出到STDOUT。

格式:

sed options script file

选项:

选项 描述
-e script 在处理输入时,将script中指定的命令添加到已有的命令中
-f file 在处理输入时,将file中指定的命令添加到已有的命令中
-n 不产生命令输出,使用print命令完成输出
  1. 格式:

sed ‘s/test/big test/‘

例如:

echo “this is a test” | sed ‘s/test/big test/‘

sed ‘s/dog/cat/‘ data.txt

  1. 执行多个命令格式:

sed -e ‘e/brown/green/;s/dog/cat/‘ data.txt

  1. 从文件中读取编辑器命令

sed -f file.sed data.txt

2. gawk程序
  1. gawk命令格式

gawk options program file

可用选项:

选项 描述
-F fs 指定行中划分数据字段的字段分隔符
-f file 从指定的文件中读取程序
-v var=value 定义gawk程序中的一个变量及其默认值
-mf N 指定要处理的数据文件中的最大字段数
-mr N 指定数据文件中的最大数据行数
-W keyword 指定gawk的兼容模式或警告等级
  1. 从命令行读取程序脚本

grawk ‘{print “Hello World!”}’

  1. 使用数据字段变量

$0:代表整个文本行

$1:代表文本行中的第1个数据字段

$2:代表文本行中的第2个数据字段

$n:代表文本行中的第n个数据字段

sde编辑器基础

1. 更多的替换选项
  1. 替换标记

s/pattern/replacement/flags

flags:

  • 数字:将新文本替换第几行模式匹配的地方

  • g:替换所有

  • p:原先行的内容要打印出来

  • w:file,将替换的结果写到文件中

  1. 替换字符

/

2. 使用地址

行寻址(line addressing)

  • 以数字形式表示行区间

  • 用文本模式来过滤出行

格式:

[address] command

address{
command1
command2
command3
}

  1. 数字方式的行寻址

sed ‘2s/dog/cat’ data.txt

sed ‘2,3s/dog/cat’ data.txt

sed ‘2,$s/dog/cat’ data.txt

  1. 使用文本模式过滤器

格式:

/pattern/command

  1. 命令组合
3. 删除行

sed ‘d’ data.txt

4. 插入和附加文本
  • insert命令i
  • append命令a

格式:

sed ‘[address]command\new line’

举例:

sed ‘i\Test line 1’

sed ‘a\test line 1’

5. 修改行

sed ‘3c\t xxxx’ data.txt

转换命令

[address]y/inchars/outchars

回顾打印