Shell编程
Shell编程Shell编程语言为高级程序设计语言,解释型语言Shell的任务:分析命令;处理通配符,重定向,管道和作业控制;搜索命令并执行Linux中常见的Shell脚本:Bourne Shell(/usr/bin/sh或者/bin/sh)Unix标准的shellBourne Again Shell(/bin/bash)Linux标准的shellC ShellzshShell一般由管理员在创建用
Shell编程
Shell编程语言为高级程序设计语言,解释型语言
Shell的任务:
分析命令;处理通配符,重定向,管道和作业控制;搜索命令并执行
Linux中常见的Shell脚本:
Bourne Shell(/usr/bin/sh或者/bin/sh) Unix标准的shell
Bourne Again Shell(/bin/bash) Linux标准的shell
C Shell
zsh
Shell一般由管理员在创建用户时,为用户指定,保存在/etc/passwd文件中,可以通过usermod更改。
Linux系统中一般默认使用bash,在编写脚本文件时,需指明bash为脚本解释器
#! /bin/bash
# (#!)为幻数,必须在第一行。通知系统采用bash解释
echo "Hello World"
注释
单行注释
# 此处为一行注释
echo "hhh" #注释从此处到一行结束
多行注释
:<< EOF
nu 1
nu 2
nu 3
EOF
:<< 字符串 该注释表示注释到该字符串再次出现时,通常为EOF,但也可以是a,abs,esdfsf等任意字符串,前后一致即可注释
运行方法
1. chmod +x test.sh #给当前脚本文件执行权限
./test.sh #当前目录下执行脚本文件
/etc/home/test.sh #采用绝对路径执行脚本文件
2. bash test.sh [参数] #运行解释器运行,可以将参数传递进入test.sh脚本文件中
3. export PATH=/bin:$PATH #将/bin加入到整个环境变量中
test.sh #在任意目录下可执行该脚本文件
元字符
元字符 | 功能 |
---|---|
回车换行 | 输入命令后要按回车 |
TAB/空格 | 命令行中分隔符 |
# | 一行注释 |
“[双引号] | 引用多个字符并允许替换 |
'[单引号] | 引用多个字符,完全不变 |
`[反引号] | 替换命令,即函数转化 |
$ | 一行的结束,或引用变量 |
& | 使命令在后台运行 |
() | 使命令在子shell中运行 |
[] | 匹配[]中的一个字符 |
{} | 在当前shell中执行,或实现扩展 |
* | 匹配0个或多个字符 |
? | 匹配单个字符 |
^ | 紧跟^后的字符开始的行,或否定 |
| | 管道命令的符号 |
; | 顺序命令的分隔符 |
<,> | 输入,输出重定向 |
/ | 根目录或路径分隔符 |
\ | 转义字符;或者续行符 |
! | 启动历史记录列表中的命令与当前命令 |
% | 指定一个作业号作为起始字符 |
~ | 表示主目录 |
注意点
三大引号:
单引号:‘abs"sf"\t’ 输出: abs"sf"\t
双引号:“ab\tc\\” 输出: ab c\ 转化:对“\”转义,对"$" 替换,对“`”进行函数执行
反引号:`date` 输出:2022年 3月 18日 …… 转化:对函数进行执行
命令的顺序执行
- command1;command2;command3;…… 顺序执行命令,若是命令后用&替换;则表示两侧的命令并发执行
- &&: command1&&command2&&…… 顺序执行,若是有command返回false,则后续的&&命令终止执行
- ||:command1||command2||…… 顺序执行,若是有command返回true,则后续的||命令终止执行
子shell环境
在()中运行的命令在子shell中执行,不影响当前环境
同样的,采用【bash 脚本】运行文件,文件在子shell中运行,不影响当前的环境
变量
shell变量分为两类:一是标准shell变量,用户登录时Shell为建立用户环境而注册的变量,也称环境变量;另一类是用户自己定义的变量,即用户变量(临时变量)。
用户变量
变量命名
以字母或下划线开始,后可以是字母、数字和下划线,注意区分大小写。
变量赋值
变量名=值 【赋值号左右没有空格】
变量引用
#! /bin/bash
a="/e" #变量声明与赋值【初始化】
echo $a #输出变量的值,用$替换
echo "$a is value of \$a"
cd "${a}tc/home" #当变量后非分隔符时,采用花括号替换
变量替换
操作符 | 描述 |
---|---|
${var} | 返回var的值,若没初始化则返回空 |
${var:-str} | 若var存在且不为空则返回var的值,否则返回str |
${var:=str} | 若var存在且不为空则返回var的值,否则将str赋给var然后返回 |
${var:?str} | 若var存在且不为空则返回var的值,否则显示:var:str |
${var:+str} | 若var存在且不为空则返回str,否则返回空 |
${#var} | 返回var的值的长度 |
${var%str} | 从var的尾部开始删除匹配str的最小部分 |
${var%%str} | 从var的尾部开始删除匹配str的最大部分 |
${var#str} | 从var的头部开始删除匹配str的最小部分 |
${var##str} | 从var的头部开始删除匹配str的最大部分 |
注意:使用最大匹配时,要结合“*”使用,如:${var%%4*}
数组变量
声明
array[key]=value #直接给下标为key的array数组元素赋值
array=( value1 value2 value3 ……) #初始化数组array,从0开始逐个赋值
array=( [1]=one [2]=two [3]=three) #指定下标赋值
数组访问
${array[key]} #引用array[key]中值
${array[*/@]} #引用array所有元素值,*扩展为一个词,@扩展为多个词,以空格隔开
数组删除
unset array[1] #删除数组中的第一个元素
unset array #删除整个array数组
计算数组大小
${#array} #等效于${#array[0]},按字节计算数组第0个元素的大小
${#array[@]} #计算数组中的元素个数
@与*
#! /bin/bash
ns=(max san [6]=zhang [35]=lsd)
a=("${ns[@]}") #元素逐个复制
echo ${a[0]} #max
b=("${ns[*]}") #所有元素当成一个元素复制到新数组
echo ${b[0]} #max san zhang lsd
环境变量
环境变量是Shell为了维护用户的使用环境而定义的一些变量。Linux环境(Shell环境)由许多变量组成,这些变量决定了用户环境的外观。
环境变量与用户变量的区别
- 环境变量可以被当前Shell下启动的子进程(子Shell) 所继承【拷贝】,而局部(用户)变量不被继承。
- 子进程的环境变量独立于父进程,子进程中对环境变量的修改不影响父进程变量的值。
环境变量 | 说明 |
---|---|
$HOME | 用户的注册目录(用户主目录),即~ |
$SHELL | 设置用户的shell类型 |
$USER | 保存当前的用户名 |
$PATH | 查找命令的目录列表,目录名用冒号隔开 |
$PWD | 保存用户当前在文件系统的位置 |
$PS1 | 定义shell的主提示符 |
$PS2 | 定义shell的副提示符 |
$IFS | 域内分隔符 |
注意
$PATH:在按照列表中目录顺序查找时,在前一个目录中查找成功后,终止查找
$PS1:主提示符即$,#(代表普通用户,root用户)
$PS2:副提示符即命令不完整时的">"符号,可继续填写命令
$IFS:分隔符为空白【空格,跳格,换行】
变量导出——export
将用户变量导出为环境变量
#! /bin/bash
echo $a
a=20
echo $a
当前环境变量中没有a,则输出结果为
20
当调用命令
export a=12
此时,a为环境变量,脚本输出结果为
12
20
但是程序在子shell环境中运行,并不会改变环境变量的值,若在命令行中输出a,值仍为12。
位置参数
位置参数及引用
位置参数也称为命令行参数,即:组成命令行的所有元素。
在Shell脚本中通过$0、$1…进行引用位置参数
输入输出
echo
echo [option] [string]
将string的内容按照option指定的方法送到屏幕上进行显示
option:
-n 输出后不换行
-e 对字符串中的特殊字符进行翻译特殊字符
\n 换行
\t 跳格
read
read [options] 变量列表
常用选项:
-a name 把词读入name数组中
-e 把一整行读入第一个变量中,其余变量为NULL
注意:读入的一行若由若干词组成,以空格或者制表符隔开。以换行符结束读入,若词的数目大于变量数,则把余下的数都放入最后一个变量;若词的数目小于变量数,则后面的变量为NULL。
测试
表达式exp可以用test exp或者[exp]来检测,这个命令检测一个表达式并返回true还是false.
- test [expression]
- [ [ expression ] ] 内括号表示可选,外括号表示test,操作数和操作符以及括号之间至少留一个空格
test命令可以使用的条件类型有三类:
- 字符串比较
- 算术比较
- 文件有关的条件测试
字符串比较:
-z str 字符串长度等于0
-n str 字符串长度不等于0
str1 = str2 str1与str2 相等
str1 != str2 str1与str2 不相等
算术与逻辑比较
符号 | 含义 |
---|---|
-eq | = |
-gt | > |
-ge | >= |
-ne | != |
-lt | < |
-le | <= |
! | not |
-o | or |
-a | and |
应用:exp1 [符号] exp2
shell程序中的**$#得到参数个数**
文件检查
-f 普通文件
-d 目录
-L/h 符号链接文件
-s 文件大小非零
-r 可读 -w 可写 -x 可执行
结构控制语句
分支语句
if-then-elif-else-fi语句
if常用于二路跳转,但也同样可以用于多路跳转。
格式如下:
第一种
if expression
then
then-command
fi
第二种
if expression
then
command-list
else
command-list
fi
第三种
if expression1
then
then1-commands
elif expression2
then
then2-commands
…
else
else-commands
fi
当条件expression为真时,执行then后的语句,否则执行elif,else,fi之后的语句。
例1:读入一个目录或者一个文件名,输出目录中文件名字或者文件内容。
#! /bin/bash
echo -n "Please enter the directory name or file name:"
read fname
if [ -d $fname ]
then
ls $fname
elif [ -f $fname ]
then
cat $fname
else
echo "input error!"
fi
例2:读入一个单词,存入一个文件中。
#!/bin/bash
echo -n enter filename: #不换行输出
read fname #读入文件名字
echo enter words:
read words #读入单词
echo $words 2>/dev/null >$fname
#2>/dev/null:忽略错误信息
#>$fname:重定向存入文件
if [ $? –eq 0 ]
#$?返回上一次命令执行的成功或者失败的状态。如果成功就是0,失败为1.。
#-eq:逻辑判断 =
then
echo Write successfully
else
echo write error
fi
case语句:
case word in #以两个分号表示结束:;;
pattern1) command_list;; #pattern可以用竖线分隔多个模式
pattern2) command_list;; #模式使用shell的文件名匹配规则。
[*) command_list;;] #*)表示匹配任意word,即其它选项之意
esac
在if嵌套超过三层后建议使用case语句。
例:输入yes或者y表示是早上,输入no或者n表示是晚上。
#! /bin/bash
echo -n "Is it morning? Please answer yes or no:"
read answer
case "$answer" in #此处缩进可以不要
yes ) echo "Good Morning"
;;
no ) echo "Good Afternoon"
;;
y ) echo "Good Morning"
;;
n ) echo "Good Afternoon"
;;
* ) echo "Sorry, answer not recognized"
;;
esac # 以esac表示case语句结束
exit 0
循环语句
for语法1:
for 变量 [ in 变量列表]
do
command-list
done
变量列表中的变量逐个赋值给变量,然后对应执行一次循环体。
#! /bin/bash
for foo in 1 fesa 3 effe 5 6fes 7
do
echo "$foo"
done
exit 0
例1:将data中的词逐行输出。
#! /bin/bash
data="a,b,c,d"
IFSBAK=$IFS #IFS分隔符,内置环境变量,存储默认的文本分隔符
IFS=, #设置分隔符为,
for item in $data
do
echo Item: $item
done
IFS=$IFSBAK #还原
for item in $data
do
echo Item: $data
done
运行结果
Item: a
Item: b
Item: c
Item: d
Item: a,b,c,d
例2:备份指定目录中所有文件到指定目录
#!/bin/bash
# -d $1:判断第一个参数是否是目录,是返回真,不是返回假
# ! -d $1:对结果取反
# 一行中程序顺序执行以分号“;”分隔语句,等同于换行
[ ! -d $1 -o ! -d $2 ]&&{ echo arguments error;exit 1;}
for file in $1/*
do
if test -f $file –a –r $file #文件是普通文件,且可读则复制
then
cp $file $2
fi #if语句结束标识
done
for语法2: (同C语言)
for ((e1;e2;e3))
do
命令列表
done
例:应用bc命令进行表达式1+1/2+1/3+····1/n计算,结果保留三位小数。
bc命令是任意精度计算器语言,通常在linux下当计算器用。
#! /bin/bash
read n
total=0.000
an=0.000
for(( num=1;num<$n;num++ ))
do
i=$num
if [ $i != 0 ]
then
#通过管道符,将输出的命令作为bc的输入,scale设置精度,而后的语句则在bc中运算
an=`echo "scale=3;1.000/$i" | bc` #计算1/n,保留三位小数
total=`echo "scale=3;$total+$an" | bc` #计算total
fi
done
echo $total
while语句:
while command
do
command-list
done
例:登陆程序
#!/bin/sh
count=3
while [ $count -gt 0 ] #count > 0时执行循环
do
echo -en "Login name:"
read logname
echo -en "Password:"
read pwd
#用户为root,密码是12345
[ $logname = "root" -a $pwd = "12345" ] && {
echo "Welcome Here!!!"
count=0
}
let count=count - 1 #计数减一
sleep 5 #休眠5ms
done
break、continue、exit
break 退出循环
continue 跳过本次循环继续
exit [n] 退出脚本,并设置退出码
退出码 | 说明 |
---|---|
0 | 成功 |
1~125 | 错误代码[特定含义] |
126 | 文件不可执行 |
127 | 命令未找到 |
127以上 | 出现一个信号(自定) |
函数
function_name() {
command_list
[return n] #return用于带回函数的返回码(0~255)
}
函数必须先定义后使用
函数在当前环境下运行,和调用它的脚本共享变量;而且可以通过把变量作为定位参数来赋值的方式传递变量。local设置函数体内的临时变量
#! /bin/bash
txt="global varible"
foo() {
local txt="local varible" #定义临时变量
echo "Function foo is executing"
echo $txt
}
echo "script starting"
foo()
echo $txt
exit 0
运行结果
script starting
Function foo is executing
local varible
global varible
数值处理
let命令
let 赋值表达式
使用C的表达式语法;
在表达式中引用变量时,前可不加“$”;
按长整形求值,不检查溢出。
表达式中有特殊字符时,须用双引号括起来。
算术运算符 | 含义 |
---|---|
-+ | 一元运算(正负) |
!~ | 逻辑非,补 |
** | 指数 |
* / % | 乘,除,取模 |
+ - | 加减 |
<< >> | 左移,右移 |
>,<,<=,>= | 大小判断 |
==,!= | 判等 |
else | 其余同C中语法 |
$((……))和$(……):两对圆括号表示算术替换,一对圆括号表示命令执行。
例:统计文件中的行数
num=$(( $(wc -l < letter.txt)/100 + 1 ))
echo $num
shell脚本跟踪与调试
通过以下方法进行调试:
bash -nvx 脚本名 #执行脚本
-n 仅做语法检查
-x 显示对命令行完成参数替换后的结果。(跟踪模式)
-v 在执行命令前将命令行原样输出一次
也可以将以上参数加到脚本幻数之后,如:
#!/bin/bash -x
更多推荐
所有评论(0)