Shell基础
1. Shell概述
1.1 shell是什么
Shell是一个命令行解释器,它为用户提供了以向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动,挂起,停止甚至是编写一些程序.
1.2 shell的分类
- Bourne家族,主要包括:sh,ksh,Bash,psh,zsh.
- C家族,主要包括:csh,tcsh
2. 脚本的执行方式
2.1 前提
- echo输出命令:
echo [选项] [内容]
选项: -e 支持反斜线控制的字符转换
控制字符 | 作用 |
---|---|
\\ | 输出 \ 本身 |
\a | 输出警告音 |
\b | 退格键,也就是左删除键 |
\c | 取消输出行尾的换行符,和"-n"选项一致 |
\e | ESCAPE键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车键 |
\t | 制表符 |
\v | 垂直制表符 |
\ Onnn | 按照八进制ASCII码表输出字符,其中0为数字零,nnn是三位八进制数 |
\xhh | 按照十六进制ASCII码表输出字符,其中hh是两位十六进制数 |
实例:
#支持反斜线控制的字符转换
[root@li ~]# echo -e 'ab\bc'
ac
[root@li ~]# echo -e 'a\tb\tc\nd\te\tf'
a b c
d e f
#不支持反斜线控制的字符转换
[root@li ~]# echo 'ab\bc'
ab\bc
[root@li ~]# echo 'a\tb\tc\nd\te\tf'
a\tb\tc\nd\te\tf
2.2 第一个脚本
vi helloworld
#!/bin/bash
#The first program
#Author: Doug Li
echo -e "This\tis\nDougLi\nfirst\tShell\tProgram"
2.3 脚本执行
- 赋予执行权限,直接运行
[root@li ~]# chmod +755 helloword.sh
[root@li ~]# ./helloword.sh
- 通过bash调用执行脚本(有无执行权限均可)
[root@li ~]# bash helloword.sh
- 格式转换dos2unix,unix2dos
3. bash的基本功能
3.1 历史命令与命令补全
3.1.1 历史命令
history [选项] [历史命令保存文件]
选项:
-c: 清空历史命令
-w: 把缓存中的历史命令写入历史命令保存文件
历史命令保存文件: ~/.bash_history
默认保存条数: /etc/profile 中的HISTSIZE=1000
历史命令的调用
- 使用上下箭头调用以前的历史命令
- 使用"!n" 重复执行第n条历史命令
- 使用"!!"重复执行上一条命令
- 使用"!字符串"重复执行最后一条以该字符串开头的命令
[root@li ~]# history | head -10
1 cd /etc/sysconfig/network-scripts/
2 ll
3 vi ifcfg-eno16777736
4 reboot
5 du -sh
6 df -h
7 docker pull hub.c.163.com/public/ubuntu:18.04
8 docker images
9 docker images -a
10 docker images --all=true
[root@li ~]# !2
ll
总用量 32
-rw-------. 1 root root 926 7月 27 11:49 anaconda-ks.cfg
-rwxr-xr-x 1 root root 98 8月 17 13:41 helloword.sh
-rwxr-xr-x. 1 root root 210 7月 27 14:37 python:3
-rwxr-xr-x 1 root root 18681 8月 17 13:45 Tetris.sh
[root@li ~]# !!
ll
总用量 32
-rw-------. 1 root root 926 7月 27 11:49 anaconda-ks.cfg
-rwxr-xr-x 1 root root 98 8月 17 13:41 helloword.sh
-rwxr-xr-x. 1 root root 210 7月 27 14:37 python:3
-rwxr-xr-x 1 root root 18681 8月 17 13:45 Tetris.sh
3.1.2 命令与文件补全
在bash中,命令与文件补全是非常方便与常用的功能,我们只要输入命令或文件时,按"Tab"键就会自动进行补全
3.2 命令别名与常用快捷键
3.2.1 命令别名
设定命令别名:alias 别名=‘原命令’
查询命令别名:alias
[root@li ~]# alias vi='vim'
[root@li ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
别名永久生效
[root@li ~]# vi ~/.bashrc
alias vi='vim'
命令的执行顺序
- 用绝对路径或相对路径执行的命令
- 执行别名
- 执行bash内部的命令
- 执行按照$PATH环境变量定义的目录查找顺序找到的第一个命令
删除别名
unalias 别名
3.2.2 常用快捷键
快捷键 | 作用 |
---|---|
ctrl+A | 把光标移动到命令行开头 |
ctrl+E | 把光标移动到命令行结尾 |
ctrl+C | 强制终止当前命令 |
ctrl+L | 清屏 |
ctrl+U | 删除/剪切光标之前的命令 |
ctrl+K | 删除/剪切光标之后的命令 |
ctrl+Y | 粘贴ctrl+K或ctrl+U剪切的内容 |
ctrl+R | 在历史命令中搜索,按下后,出现搜索界面,输入搜索内容,就从历史命令中查找 |
ctrl+D | 退出当前终端 |
ctrl+Z | 暂停,并放入后台 |
ctrl+S | 暂停屏幕输出 |
ctrl+Q | 回复屏幕输出 |
3.3 输入输出重定向
3.3.1 标准输入输出
设备 | 设备文件名 | 文件描述符 | 类型 |
---|---|---|---|
键盘 | /dev/stdin | 0 | 标准输入 |
显示器 | /dev/stdout | 1 | 标准输出 |
显示器 | /dev/stdout | 2 | 标准错误输出 |
3.3.2 输出重定向
类型 | 符号 | 作用 |
---|---|---|
标准输出重定向 | 命令 > 文件 | 以覆盖方式,把命令正确输出,输出到指定的文件或设备当中 |
命令 >> 文件 | 以追加方式,把命令正确输出,输出到指定的文件或设备当中 | |
标准错误输出重定向 | 命令 2> 文件 | 以覆盖方式,把命令的错误输出,输出到指定的文件或设备当中 |
命令 2>> 文件 | 以追加方式,把命令的错误输出,输出到指定的文件或设备当中 | |
正确和错误输出同时保存 | 命令 > 文件 2>&1 | 以覆盖方式,把命令的正确和错误输出,输出到指定的文件或设备当中 |
命令 >> 文件 2>&1 | 以追加方式,把命令的正确和错误输出,输出到指定的文件或设备当中 | |
命令 &>> 文件 | 以追加方式,把命令的正确和错误输出,输出到指定的文件或设备当中 | |
命令 &>> 文件 | 以追加方式,把命令的正确和错误输出,输出到指定的文件或设备当中 | |
命令 >> 文件1 命令 2>>文件2 | 把正确输出追加到文件1,错误输出追加到文件2 |
# /dev/null --相当于垃圾箱
[root@li ~]# ls &>/dev/null
3.3.3 输入重定向
wc [选项] [文件名]
选项
-c 统计字节数
-w 统计单词数
-l 统计行数
[root@li ~]# wc anaconda-ks.cfg
39 91 926 anaconda-ks.cfg
[root@li ~]# wc -l anaconda-ks.cfg
39 anaconda-ks.cfg
[root@li ~]# wc -w anaconda-ks.cfg
91 anaconda-ks.cfg
[root@li ~]# wc -c anaconda-ks.cfg
926 anaconda-ks.cfg
[root@li ~]#
3.4 多命令顺序执行与管道符
3.4.1 多命令顺序执行
多命令执行符 | 格式 | 作用 |
---|---|---|
; | 命令1 ; 命令2 | 多个命令顺序执行,命令之间没有任何逻辑联系 |
&& | 命令1 && 命令2 | 逻辑与 当命令1正确执行,则命令2才会执行;当命令1执行不正确,命令2不执行 |
|| | 命令1 || 命令2 | 逻辑或 当命令1执行不正确,命令2才执行 ; 命令1正确执行,命令2 不执行 |
dd 是 Linux/UNIX 下的一个非常有用的命令,作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。
dd if=输入文件 of=输出文件 bs=字节数 count=个数
选项
if=输入文件 指定源文件或源设备
of=输出文件 指定目标文件或目标设备
bs=字节数 执行一次输入/输出多少字节,即把这些字节看作一个数据块
count=个数 指定输入输出多少个数据块
[root@li ~]# ls ; cd /etc/ ; pwd
anaconda-ks.cfg helloword.sh python:3 Tetris.sh
/etc
[root@li ~]# ls asdbfdf && echo yes
ls: 无法访问asdbfdf: 没有那个文件或目录
[root@li ~]# ls anaconda-ks.cfg && echo yes
anaconda-ks.cfg
yes
[root@li etc]# date;dd if=/dev/zero of=/root/testfile bs=1k count=10000;date
2019年 08月 17日 星期六 16:10:10 CST
记录了10000+0 的读入
记录了10000+0 的写出
10240000字节(10 MB)已复制,0.019049 秒,538 MB/秒
2019年 08月 17日 星期六 16:10:10 CST
判断一条命令是否正确 命令 && echo yes || echo no
[root@li ~]# ls &>/dev/null && echo yes || echo no
yes
[root@li ~]# lss &>/dev/null && echo yes || echo no
no
3.4.2 管道符
命令1 | 命令2
命令1 的正确输出作为命令2的操作对象
[root@li ~]# ll -a /etc/ |more
[root@li ~]# netstat -an |grep "ESTABLISHED"
grep [选项] “搜索内容” 文件名
选项
-i: 忽略大小写
-n: 输出行号
-v: 反向查找
–color=auto 高亮关键字
[root@li ~]# grep "root" --color=auto -n /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
3.5 通配符与其他特殊符号
3.5.1 通配符
通配符 | 作用 |
---|---|
? | 匹配一个任意字符 |
* | 匹配0个或任意多个任意字符,也就是可以匹配任何内容 |
[] | 匹配中括号中任意一个字符,例如:[abc]代表一定匹配一个字符,或者是a,或者b,或者c |
[-] | 匹配中括号中任意一个字符,-代表一个范围,例如:[a-z],代表匹配一个小写字母 |
[^] | 逻辑非,表示匹配不是括号中内的一个字符,例如: [^0-9] 代表匹配一个不是数字的字符 |
[root@li tmp]# rm -rf *
[root@li tmp]# touch abc
[root@li tmp]# touch abcd
[root@li tmp]# touch 012
[root@li tmp]# touch 0abc
[root@li tmp]# ls ?abc
0abc
[root@li tmp]# ls [0-9]*
012 0abc
[root@li tmp]# ls [^0-9]*
abc abcd
3.5.2 Bash中的其他特殊符号
符号 | 作用 |
---|---|
’ ’ | 单引号,在单引号中所有的特殊符号,如 “$“和”`”(反引号)都没有特殊含义 |
" " | 双引号,在双引号中特殊符号都没有特殊含义,但是"$“和”`"(反引号)和" \ “是例外,拥有"调用变量的值”,“引用命令”,"转义符"的特殊含义 |
`` | 反引号,反引号括起来的内容都是系统命令,在bash中会先执行它和$()的作用一样,推荐使用$(), ``反引号不易识别 |
$() | 和反引号作用一样,用来引用系统命令 |
# | 在shell脚本中,#开头的行代表注释 |
$ | 用于调用变量的值,如果需要调用变量name的值时,需要用$name的方式得到变量的值 |
\ | 转义符,跟在\之后的特殊字符号,将失去特殊含义,变为普通字符串,\$将输出"$"符号,而不是变量引用 |
4. bash变量
4.1 用户自定义变量
变量定义:计算机的基本内存单元,其中存放的值是可以改变的.
变量规则:由字母,数字,下划线组成,在Bash中默认类型是字符串型,如果要进行数值运算,则必须指定变量类型为数值型.
- 变量用等号连接值,等号左右两侧不能有空格.
- 变量的值如果有空格,需要使用单引号或双引号包括.
- 在变量的值中,可以使用"\"转义符.
- 如果需要增加变量的值,那么可以进行变量值的叠加,不过变量需要用双引号包含"$变量名"或用${变量名}包含.
- 如果是把命令的结果作为变量值赋予变量,则需要使用反引号或$()包含命令.
- 环境变量名建议大写,便于区分.
变量调用:echo $name
变量查看:set
变量删除:unset name
[root@li tmp]# name="dougli"
[root@li tmp]# aa=123
[root@li tmp]# aa="$aa"456
[root@li tmp]# aa=${aa}789
4.2 环境变量
环境变量: 用户自定义变量只在当前的shell中生效,而环境变量会在当前shell和这个shell的所有子shell当中生效,如果把环境变量写入相应的配置文件,那么这个环境变量就会在所有的shell中生效.
设置环境变量
- 申明变量
export 变量名=变量值- 查询变量
env- 删除变量
unset 变量名
#当前shell
[root@li ~]# pstree
systemd─┬─NetworkManager─┬─dhclient
│ └─2*[{NetworkManager}]
├─sshd───sshd───bash───pstree
#当前shell的子shell
[root@li ~]# bash
[root@li ~]# pstree
systemd─┬─NetworkManager─┬─dhclient
│ └─2*[{NetworkManager}]
├─sshd───sshd───bash───bash───pstree
#设置环境变量
[root@li ~]# name=liwei
[root@li ~]# export name
[root@li ~]# env
XDG_SESSION_ID=1
HOSTNAME=li
SHELL=/bin/bash
TERM=vt100
HISTSIZE=1000
SSH_CLIENT=192.168.108.1 50502 22
SSH_TTY=/dev/pts/0
name=liwei
4.3 位置参数变量
位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的.
位置参数变量 | 作用 |
---|---|
$n | n为数字,$0代表命令本身,$1-9代表第一到第九个参数,十以上的参数需要用大括号包含,如9代表第一到第九个参数,十以上的参数需要用大括号包含,如9代表第一到第九个参数,十以上的参数需要用大括号包含,如{10} |
$* | 这个变量代表命令行中所有参数,$*把所有的参数看成一个整体 |
$@ | 这个变量也代表命令行中的所有的参数,不过把每个参数区分对待 |
$# | 这个变量代表命令行中所有参数的个数 |
#新增脚本
[root@li sh]# vi canshu.sh
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
#增加可执行权限
[root@li sh]# chmod +x canshu.sh
#执行结果
[root@li sh]# ./canshu.sh 1 2
./canshu.sh
1
2
求和案例
[root@li sh]# vi sum.sh
#!/bin/bash
#变量求和
sum=$(($1+$2))
echo $sum
[root@li sh]# chmod +x sum.sh
[root@li sh]# ./sum.sh 1 2
3
[root@li sh]# vi canshu3.sh
#!/bin/bash
echo $#
echo $*
echo $@
[root@li sh]# chmod +x canshu3.sh
[root@li sh]# ./canshu3.sh 1 2 3
3
1 2 3
1 2 3
[root@li sh]# vi canshu4.sh
#!/bin/bash
#!/bin/bash
for i in "$*"
#$*中的所有参数看作是一个整体,所以这个for循环只会循环一次
do
echo "The param is:$i"
done
x=1
for y in "$@"
#$@中的每个参数都看成是独立的,所以"$@"中有几个参数,就会循环几次
do
echo "The param is:$y"
echo $(($x+1))
done
[root@li sh]# ./canshu4.sh 1 2 3
The param is:1 2 3
The param is:1
2
The param is:2
2
The param is:3
2
4.4 预定义变量
预定义变量:是bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的
预定义变量 | 作用 |
---|---|
$? | 最后一次执行的命令返回的状态,0代表成功,非0(具体哪个数由程序决定)代表失败 |
$$ | 当前进程的进程号(PID) |
$! | 后台运行的最后一个进程的进程号 |
[root@li sh]# vi variable.sh
#!/bin/bash
#Author:DougLi
echo "The current process is $$"
#输出当前进程的PID
#这个PID就是variable.sh这个脚本执行时,生成的进程的PID
find /root -name canshu.sh &
#使用find命令在root目录下查找hello.sh文件
#符号&的意思是把命令放入后台执行
echo "The last one Daemon process is $!"
[root@li sh]# ./variable.sh
The current process is 1425
The last one Daemon process is 1426
[root@li sh]# /root/sh/canshu.sh
接受键盘输入:read [选项] [变量名]
- -p “提示信息”:在等待read输入时,输出提示信息
- -t 秒数 : read 命令会一直等待用户输入,使用此选项可以指定等待时间
- -s: 隐藏输入的数据
- -n 字符数:read命令只接受指定的字符数,就会执行
[root@li sh]# vi canshu5.sh
echo -e "\n"
#!/bin/bash
#Author:DougLi
read -t 30 -p "Please input your name: " name
#提示"请输入姓名"并等待30s,把用户的输入保存到变量name中
echo "name is $name"
read -s -t 30 -p "Please enter your age: " age
#年龄是隐私,所以我们使用"-s"选项隐藏输入
echo -e "\n"
echo "Age is $age"
read -n 1 -t 30 -p "Please select your gender[M/F]: " gender
#使用"-n 1"选项只接收一个字符串就会执行(无需回车)
echo -e "\n"
echo "sex is $gender"
[root@li sh]# ./canshu5.sh
Please input your name: DougLi
name is DougLi
Please enter your age:
Age is 29
Please select your gender[M/F]: F
sex is F
4.5 数值运算与运算符
基本语法
- $((运算式)) 或 $[运算式]
- expr +,-,*,/,% 加,减,乘,除,取余. 注意:运算符之间要有空格
shell script
[root@li datas]# expr 1 \* 2
2
[root@li datas]# expr 1 - 2
-1
[root@li datas]# expr `expr 2 + 3` \* 4
20
[root@li datas]# s=$[(2+3)*4]
[root@li datas]# echo $s
20