Linux Shell 编程基础详解——吐血整理,墙裂推荐!
第一部分:Linux Shell 简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
当一个用户登陆linux 系统后,系统就会为该用户创建一个shell程序。
Shell的版本:
- Bourne Shell:是贝尔实验室开发的,unix普遍使用的shell,在编程方面比较优秀,但在用户交互方面没有其他shell优秀。
- BASH:是GNU的Bourne Again Shell,是GNU操作系统上默认的shell,在bourne shell基础上增强了很多特性,如命令补全,命令历史表等等
- Korn Shell:是对Bourne Shell 的发展,在大部分内容上与Bourne Shell兼容,集成了C Shell和Bourne shell优点。
- C Shell:是SUN公司Shell的BSD版本,语法与c语言相似,比bourne shell 更适合编程
第二部分 shell 程序设计基础
2.1 shell输入输出
2.1.1 echo
echo命令可以显示文本行或变量取值,或者把字符串输入到文件中
格式: echo string
echo的常用功能:\c 不换行 \f 不进纸 \t 跳格 \n 换行
note:
对于linux系统,必须使用-e选项来使以上转义符生效
例:
$ echo -e "hello\tboy"
hello boy
echo命令对特殊字符敏感,如果要输出特殊字符,需要用\屏蔽其特殊含义。
常用的特殊字符:双引号"" 反引号`` 反斜线\
例:
$ echo "\"\"" //想输出""
""
2.1.2 read
read命令从键盘或者文件的某一行文本中读入信息,并将其赋给一个变量。
如果只指定了一个变量,read会把所有的输入赋给该变量,直至遇到第一个文件结束符或回车
格式: read var1 var2 …
例1:
chenshifengdeMacBook-Pro:~ chenshifeng$ read name
Hello I am superman
chenshifengdeMacBook-Pro:~ chenshifeng$ echo $name
Hello I am superman
如果输入的值个数多于变量个数,多余的值会赋给最后一个变量:
例2:
chenshifengdeMacBook-Pro:~ chenshifeng$ read name surname
John Mike Kate
chenshifengdeMacBook-Pro:~ chenshifeng$ echo $surname
Mike Kate
chenshifengdeMacBook-Pro:~ chenshifeng$
2.1.3 cat
cat可以用来显示文件,并且支持将多个文件串连接后输出
note:该命令一次显示完整个文件,若想分页查看,需使用more
格式: cat [ options ] filename1 … filename2 …
常用options:
- -v 显示控制字符
- -n 对所有输出行进行编号
- -b 与-n相似,但空白行不编号
例:
$ cat file1 file2 file3 // 同时显示三个文件
$ cat –b file1 file2 file3
2.1.4 管道 |
可以通过管道把一个命令的输出传递给另外一个命令做为输入
格式: 命令1 | 命令2
例:
$ cat test.txt | grep 'hello'
2.1.5 tee
把输出的一个副本输送到标准输出,另一个副本拷贝到相应的文件中
如果想看到输出的同时,把输出也同时拷入一个文件,这个命令很合适
格式: tee -a file
- -a 表示文件追加到末尾
- file 表示保存输出信息的文件
tee命令一般和管道符|结合起来使用
例:
$ who | tee who.info // 该命令的信息返回在屏幕上,同时保存在文件who.info中
$ who | tee who.info
chenshifeng console Jan 9 12:56
chenshifeng ttys000 Jan 9 13:27
chenshifeng ttys004 Jan 9 19:11
chenshifeng ttys005 Jan 10 00:12
$ cat who.info
chenshifeng console Jan 9 12:56
chenshifeng ttys000 Jan 9 13:27
chenshifeng ttys004 Jan 9 19:11
chenshifeng ttys005 Jan 10 00:12
2.1.6 标准输入,输出和错误
当我们在shell中执行命令的时候,每个进程都和三个打开的文件相联系,并使用文件描述符来引用这些文件,见下表
文件 | 文件描述符 |
---|---|
输入文件-标准输入 | 0 |
输出文件-标准输出 | 1 |
错误输出文件-标准错误 | 2 |
系统中实际上有12个描述符,可以任意使用文件描述符3-9 | |
标准输入 对应文件描述符0,是命令的输入,缺省键盘 | |
标准输出 对应文件描述符1,是命令的输出,缺省屏幕或文件 | |
标准错误 对应文件描述符2,是命令错误的输出,缺省屏幕或文件 | |
利用文件重定向功能对命令的标准输入,输出和错误进行修改。 | |
常用文件重定向命令: |
command > file: 标准输出重定向到一个文件,错误仍然输出屏幕
command >> file: 标准输出重定向到一个文件(追加)
command 1> file: 标准输出重定向到一个文件
command 2>> file: 标准错误重定向到一个文件(追加)
command >file 2>&1: 标准输出和标准错误一起重定向到一个文件
command >>file 2>&1: 标准输出和标准错误一起重定向到一个文件(追加)
command < file1 >file2: 以file1做为标准输入,file2做为标准输出
command <file: 以file做为文件标准输入
结合使用标准输出和标准错误
$ cat hello 1>myfile.out 2>myerror.out
合并标准输出和标准错误
$ cat >>mylog.out 2>&1 <hello
2.2 shell后台执行命令
2.21 cron
cron是系统的调度进程,可在无人干预的情况下运行作业,通过crontab的命令允许用户提交,编辑或者删除相应的作业。
每个用户都可以有一个crontab文件来保存调度信息,通过该命令运行任意一个shell脚本或者命令
在大的系统中,系统管理员可以通过/etc/cron.allow和/etc/cron.deny这两个文件来禁止或允许用户拥有自己的crontab文件
crontab的域
第1列 分钟0~59
第2列 小时0~23(0表示子夜)
第3列 日1~31
第4列 月1~12
第5列 星期0~6(0表示星期天)
第6列 要运行的命令
crontab格式: 分<>时<>日<>月<>星期<>要运行的命令
<>表示空格
note:如果要表示范围的话,如周一到周五,可以用1-5表示
如果要列举某些值,如周一、周五,可以用1,5表示
例1:
30 21 * * * /apps/bin/cleanup.sh
例2:
0,30 18-23 * * * /apps/bin/dbcheck.sh
crontab的命令选项
格式:crontab [ -u user ] -e -l -r
其中
- -u 用户名,如果使用自己的名字登陆,就不用使用-u选项
- -e 编辑crontab文件
- -l 列出crontab文件中的内容
- -r 删除crontab文件
创建一个新的crontab文件
1 创建一个文件,建议名为
0,10,20,30,40,50 * * * * /bin/echo "hello boy"
保存退出
2 提交刚刚创建的cron文件shifengcron
$ crontab shifengcron
$ ls /var/spool/cron/ 是否生成文件shifengcron
列出crontab文件
$ crontab –l
$ crontab –l > $HOME/mycron 可以通过这种方法对crontab进行备份
编辑crontab文件
$ crontab -e
修改后保存退出,cron会对其进行必要的完整性检查
删除crontab文件
$ crontab –r
crontab文件的恢复
如果误删了crontab文件,假设在$HOME目录下还有备份,可以将这个备份文件拷贝到/var/spool/cron/
$ crontab <filename>
note:filename是备份的crontab文件的名字
2.22 at
at命令允许用户向cron守护进程提交作业,使其在稍后的时间运行,这个时间可以是10min以后,也可能是几天以后,但如果时间比较长,建议还是使用crontab
格式:at [ -f script ] [ -m -l -r ] [ time ] [ date ]
- -f script 是要提交的脚本或命令
- -m 作业完成后给用户发邮件
- -r 清除某个作业,需要提供作业标识id
- time 作业执行的时间格式可以为:HH. MM ,HH:MM
- H代表小时,M代表分钟
- date 日期格式可以是月份数或日期数,而且at命令可以识别诸如today,tomorrow这样的词
可以通过命令行方式或者at命令提示符方式来提交作业,一般来讲,如果提交多个命令,可以使用at命令提示符;如果提交的是shell脚本,可以使用命令行方式
例:提示符方式:
$ at 01:15
at > echo “hello”
at > echo “boy” >/home/wuxh/at.log
at > <EOT>
note:EOT是Ctrl+D,任务执行后,会给当前用户发送邮件,通过mail命令可以查看相关信息,也可以将信息重定向到文件
例:提交shell脚本方式
$ at 3:00pm tomorrow –f /home/wuxh/hello.sh
note:该脚本将在明天下午3点运行,使用脚本方式,要加参数-f
列出at任务,格式:at -l
例:
$ at -l
5 2021-01-17 11:20 a root
note: 第一个是作业标识id;第二个是日期;第三个是时间;a代表at;第四个代表创建任务的用户
清除at任务
格式:at -r
$ at –r [ job no]
例:$ at -r 5
note:不接job no将清除所有未执行的任务,接具体job id将清楚对应的任务
2.23 &
当在前台运行某个作业时,终端被该作业占据;而当它在后台运行时,它不会占据终端
可以借助&命令把作业放到后台执行
格式: 命令 &
注:
1 .需要用户交互的命令不要放在后台执行,否则机器一直等待
2 .后台程序在执行时,执行结果仍然会输出到屏幕,干扰我们的工作,建议将这样的信息重定向到某个文件
即:command > out.file 2>&1 &
将标准输入错误输出都定向到一个out.file的文件中
例:$ find /etc/ -name "hello" -print >find.dt 2>&1 &
2.3 引号
"" | 双引号 |
---|---|
` | 反引号 |
'' | 单引号 |
\ | 反斜线 |
2.31 双引号
可引用除字符$,`,\
外的任意字符或者字符串,对$,`,\
敏感
例1:
$ echo "hello"
hello
例2:
$ echo "$$"
8311 ///想输出字符$$ 结果看到的是数值8311
$ echo "\$$" //对特殊字符需要反斜线屏蔽其特殊含义
$$ //得到想要的结果
例3:
$ echo "`V_V`" //想输出`V_V`字样 结果得到错误信息
$ echo "\`V_V\`" //得到`V_V`输出
2.32 单引号
单引号和双引号的用法基本类似,不同的是单引号对特殊字符不敏感,可以将其做为普通字符输出出来
例:
$ echo '$$' //结果 $$ 不用借助\进行屏蔽
$ echo '`V_V`' //结果`V_V`,和前面双引号比较
2.33 反引号
该命令用于设置系统命令的输出到变量,shell将反引号中的内容做为命令执行。
例1:
$ echo `hello`
-bash: hello: command not found
例2:
$ echo `date`
2021年 1月17日 星期日 23时40分18秒 CST
反引号可以和双引号结合起来使用:
例3:
$ echo "The date today is `date`"
The date today is 2021年 1月17日 星期日 23时41分15秒 CST
2.34 反斜线
如果一个字符有特殊含义,为防止shell误解其含义,可用\屏蔽该字符
具有特殊含义的字符
------------------------------------------------------------------------------------
& * ^ $ ` “ |
------------------------------------------------------------------------------------
例1 :
$ echo "$$" //在屏幕上输出$$字符,结果显示3853
$ echo "\$$" //用反斜线屏蔽,防止shell误解,结果显示$$
例2:
$ echo * //在屏幕上输出*字符,结果输出当前目录下内容
$ echo \* //用反斜线屏蔽,防止shell误解,输出*字符
2.4 shell变量,参数
2.4.1 系统变量
系统变量适用于所有用户进程,可以在命令行中设置,但用户注销时这些值将丢失,最好在.bash_profile中进行定义,或者/etc/profile
传统上,所有环境变量都大写,且必须用export命令导出
设置环境变量:
var_name=value; export var_name
或者:
var_name=value
export var_name
又或者
export var_name=value
查看环境变量:
echo $var_name
- env 该命令可查看所有系统环境变量
- unset var_name 清除系统环境变量
嵌入shell变量
一般来讲,bourne shell有一些预留的环境变量名,这些变量名不能做其他用途,通常在/etc/profile中建立这些嵌入的环境变量,但这不绝对,取决于用户
shell的变量列表:
CDPATH; EXINIT; HOME; IFS; LOGNAME; MAIL;MAILCHECK; PATH; PS1; PS2; SHELL; TERMINFO;TERM; TZ
2.4.2 用户变量
在用户shell生命周期的脚本中使用,不同的用户可以定义各自的用户变量 ~/.bashrc
用法:
var_name=value
显示变量:
echo $var_name
or echo ${var_name} //建议使用
清除变量:
unset var_name
显示用户所有变量:set
测试变量是否设置:echo ${var:=value} 若未设置或未初始化,可用新值
使用变量保存系统命令参数
例:
$ SOURCE="/etc/passwd"
$ DEST="/home/chenshifeng/
$ cp $SOURCE $DEST
设置只读变量
可设置某个变量为只读方式,只读变量不可更改,否则系统返回错误
用法:
var_name=value
readonly var_name
例:
$ myvar="100"
$ readonly myvar
$ myvar="200"
$ -bash: myvar: readonly variable
2.4.3 位置变量
位置变量属于只读变量
作用:向shell脚本传递参数,参数个数可以任意多,但只有前9个被访问到,shift命令可以更改这个限制。
每个访问参数前加$,
第一个参数为0,表示预留保存实际脚本名字,无论脚本是否有参数,此值均可用,如:给脚本test传递信息:
Would you like to do it
$0 | $1 | $2 | $3 | $4 | $5 | $6 | $7 | $8 | $9 |
---|---|---|---|---|---|---|---|---|---|
脚本名字 | would | you | like | to | do | it |
例:$ vi test
#!/bin/sh
echo "The full name is : $0 "
echo "The script name is : `basename $0`"
echo "The first parameter is :$1"
echo "The second parameter is :$2"
echo "The third parameter is :$3"
echo "The fourth parameter is :$4"
echo "The fifth parameter is :$5"
echo "The sixth parameter is :$6"
echo "The seventh parameter is :$7"
echo "The eighth parameter is :$8"
echo "The ninth parameter is :$9"
保存文件,执行 $ ./test would you like to do it
The full name is : ./test
The script name is : test
The first parameter is :would
The second parameter is :you
The third parameter is :like
The fourth parameter is :to
The fifth parameter is :do
The sixth parameter is :it
The seventh parameter is :
The eighth parameter is :
The ninth parameter is :
note:上例中
$0
返回的信息中包含路径名,如果只想得到脚本名称,可以借助basename,将脚本中第一句修改为:
echo "The script name is : \`basename \$0\` "
保存文件,执行 ./test would you like to do it
note:basename 用``向系统命令传递参数
可以在脚本中向系统命令传递参数
$ vi findfile
#!/bin/sh
find / -name $1
保存,执行
$ ./findfile passwd
2.4.4 特定变量
特定变量属于只读变量,反映脚本运行过程中的控制信息
特定的shell变量列表:
变量 | 说明 |
---|---|
$# | 传递到脚本的参数个数(常用) |
$* | 以一个单字符串的形式显示所有向脚本传递的参数,与位置变量 不同,此项参数可超过9个 |