Linux ~ shell。
文章目录
- Linux ~ shell。
- shell。
- shell 概述。
- what。
- shell 分类。
- shell 基础 ~ 脚本执行方式。
- 第一个脚本。
- bash 的基本功能。
- 多命令顺序执行与管道符。
- 输入输出重定向。
- 输出重定向。
- 输入重定向。
- 多命令顺序执行与管道符。
- 管道符。
- 通配置符与其他特殊符号。
- Bash 中其他特殊符号。
- Bash 的变量。
- 用户自定义变量。
- 什么是变量。
- 变量设置规则。
- 变量分类。
- 本地变量。
- 环境变量。
- 设置环境变量。
- 系统常见环境变量。
- 位置参数变量。
- 预定义变量。
- Bash 的运算符。
- 数值运算与运算符。
- declare 声明变量类型。
- 数值运算 ~ 方法 1。
- 方法 2 ~ expr 或 let 数值运算工具。
- 方法 3 ~ $((运算式)) 或 $[运算式] ~ 推荐使用!!
- 运算符。
- 变量测试与内容替换。
- 环境变量配置文件。
- 环境变量配置文件简介。
- 环境变量配置文件作用。
- 其他配置文件和登录信息。
- Shell 编程。
- 字符截取命令。
shell。
shell 概述。
shell 脚本的执行方式。
shell 的基本功能。
shell 的变量。
shell 的运算符。
环境变量配置文件。
shell 概述。
what。
shell 是一个命令行解释器,ta 为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序。用户可以用 shell 来启动、挂起、停止甚至是编写一些程序。
外层应用程序 -> shell 命令解释器 -> 内核 -> 硬件。
Windows 图形界面也是 shell。
shell 还是一个功能相当强大的编程语言,易编写,易调试,灵活性较强。shell 是解释执行的脚本语言,在 shell 中可以直接调用 Linux 系统命令。
shell 分类。
-
Bourne Shell。
从 1979 起 Unix 就开始使用 Bourne Shell,Bourne Shell 的主文件名为 sh。 -
C Shell。
C Shell 主要在 BSD 版的 Unix 系统中使用,其语法的 C 语言相类似而得名。
Shell 的两种主要语法类型有 Bourne 和 C,这两种语法彼此不兼容。
Bourne 家族主要包括 sh、ksh、Bash、psh、zsh。
C 家族主要包括 csh、tcsh。
Linux 主要 Bash。Bash 和 sh 兼容。
Linux 支持的 shell。
/etc/shells
[geek@localhost ~]$ cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
[geek@localhost ~]$ sh
sh-4.2$
sh-4.2$ exit
exit
[geek@localhost ~]$ bash
[geek@localhost ~]$
[geek@localhost ~]$ exit
exit
[geek@localhost ~]$ sh
sh-4.2$
sh-4.2$ exit
exit
[geek@localhost ~]$ bash
[geek@localhost ~]$
[geek@localhost ~]$ exit
exit
[geek@localhost ~]$
shell 基础 ~ 脚本执行方式。
echo 输出命令。
echo [选项] [输出内容]
-e。支持反斜线控制的字符转换。
控制字符 | 作用 |
---|---|
\ | 输出 \ 文本。 |
\a | 输出警告音。 |
\b | 退格键,也就是向左删除键。 |
\c | 取消输出行末的换行符。和 -n 选项等效。 |
\e | ESCAPE 键。 |
\f | 换页符。 |
\n | 换行符。 |
\r | 回车符。 |
\t | 制表符。也就是 Tab 键。 |
\v | 垂直制表符。 |
\0nnn | 按照八进制 ASCII 码表输出字符。其中 0 为数字领零,nnn 是三位八进制数。 |
\xhh | 按照十六进制 ASCII 码表输出字符。其中 hh 是两位十六进制数。 |
[geek@localhost ~]$ echo -e "a\tb\tc\t\nd\te\tf"
a b c
d e f
[geek@localhost ~]$ echo -e "\x61\t\x62\t\x63\t\n\x64\t\x65\tf"
a b c
d e f
[geek@localhost ~]$
[root@localhost ~]# echo 'ab\bc'
ab\bc
[root@localhost ~]# echo -e 'ab\bc'
ac # \b 退格。
内容有空格,要加引号。
[geek@localhost ~]$ echo "hello world"
hello world
[geek@localhost ~]$ echo "hello world!"
-bash: !": event not found
[geek@localhost ~]$ echo 'hello world!'
hello world!
[geek@localhost ~]$ echo -e "\e[1;31m abcd\e[0m"
abcd
# 输出颜色。
#30m。黑色。#31m。红色。#32m。绿色。#33m。黄色。
#34m。蓝色。#35m。洋红。#36m。青色。#37m。白色。
第一个脚本。
[geek@localhost ~]$ vim hello.sh
[geek@localhost ~]$ cat hello.sh
#! /bin/bash
# The First Shell Program.
# Author: geek(Email: YifanLiGeek@gmail.com)
echo -e "Geek ~ hello world."
-
#!/bin/bash
表示 Shell 文件。 -
脚本执行。
1、赋予执行权限,直接运行。
[geek@localhost ~]$ ./h
-bash: ./h: No such file or directory
[geek@localhost ~]$ chmod 755 hello.sh
[geek@localhost ~]$ ./hello.sh
Geek ~ hello world.
2、 通过 bash 调用执行脚本。
[geek@localhost ~]$ bash hello.sh
Geek ~ hello world.
- cat -A hello.sh # 查看文件所有内容(包括隐藏内容)。
[geek@localhost ~]$ cat -A hello.sh
#! /bin/bash$
# The Ffirst Shell Program.$
# Author: geek(Email: YifanLiGeek@gmail.com)$
$
echo -e "Geek ~ hello world."$
$ ~ Linux 回车符。
^M ~ Windows 回车符。
dos2unix 文件名
unix2dos 文件名
bash 的基本功能。
历史命令与命令补全。
- 历史命令。
[root@localhost ~]# history [选项] [历史命令保存文件]
-c ~ 清空历史命令。
-w ~ 把缓存中的历史命令立即写入历史命令保存文件。
~/.bash_history
(登录的用户退出后才会自动写入)。
历史命令默认保存 1000 条。可以在环境变量配置文件 /etc/profile 中进行修改。
HISTSZE=1000
- 历史命令的调用。
↑ ↓ 箭头调用以前的历史命令。
!n ~ 重复执行第 n 条历史命令。
!! ~ 重复执行第上一条历史命令。
!字串 ~ 重复执行最后一条以该字符串开头的命令。
- Tab。
命令与文件补全。
命令别名与常用快捷键。
[root@localhost ~]# alias 别名='原命令'
# 设置命令别名。
[root@localhost ~]# alias
# 查询命令别名。
[geek@localhost ~]$ alias
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 vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
- 命令执行时的顺序。
第一顺位执行用绝对路径或相对路径执行的命令。
第二顺位执行别名。
第三顺位执行 bash 的内部命令。
第四顺位执行按照 $PATH 环境变量定义的目录查找顺序找到的第一个命令。
[root@localhost shell_test]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
让别名永久生效。
[root@localhost ~]# vim /root/.bashrc
# 让 root 永久生效。
# 让 user1 永久生效。
vi /home/user1/.bashrc
删除别名。
[root@localhost ~]# unalias 别名
bash 常用快捷键。
-
Ctrl + A。
把光标移动到命令行开头。如果我们输入的命令过长,想要把光标移动到命令行的开头使用。 -
Ctrl + E。
把光标移动到命令行结尾。 -
Ctrl + C。
强制终止当前命令。 -
Ctrl + L。
清屏。相当于 clear 命令。 -
Ctrl + U。
删除或剪切光标之前的命令。我输入了一个很长的命名,不用使用退格键一个一个字符的删除。使用这个命令会更加方便。 -
Ctrl + K。
删除或剪切光标之后的命令。 -
Ctrl + Y。
粘贴 Ctrl + U 或 Ctrl + K 剪切的内容。 -
Ctrl + R。
在历史命令中搜索。按下 Ctrl + R 之后,就会出现搜索界面,只要输入搜索内容,就会从历史命令中搜索。 -
Ctrl + D。
退出当前终端。 -
Ctrl + Z。
暂停,并放入后台。这个快捷键会牵扯工作管理的内容。在系统管理章节详细介绍。 -
Ctrl + S。
暂停屏幕输出。 -
Ctrl + Q。
恢复屏幕输出。
多命令顺序执行与管道符。
输入输出重定向。
- 标准输入输出。
设备。 | 设备文件名。 | 文件描述符。 | 类型。 |
---|---|---|---|
键盘。 | /dev/stdin | 0 | 标准输入。 |
显示器。 | /dev/stdout | 1 | 标准输出。 |
显示器。 | /dev/stderr | 2 | 标准错误输出。 |
输出重定向。
标准输出重定向。
-
命令 > 文件。
以覆盖的方式,把命令的正解输出输出到指定的文件或设备中。 -
命令 >> 文件。
以追加的方式,把命令的正解输出输出到指定的文件或设备中。
标准错误输出重定向。 -
错误命令 2> 文件。
以覆盖的方式,把命令的错误输出输出到指定的文件或设备中。 -
错误命令 2>> 文件。
以追加的方式,把命令的错误输出输出到指定的文件或设备中。
正解输出和错误输出同时保存。
- 命令 > 文件 2>&1【先把错误输出(2)保存在正确输出(1)中,再一起保存到文件。】
以覆盖的方式,把正解输出和错误输出都保存到同一文件中。
[geek@localhost ~]$ lst >> log.txt 2>&1
[geek@localhost ~]$ cat log.txt
-bash: lst: command not found
[geek@localhost ~]$ ls >> log.txt 2>&1
[geek@localhost ~]$ cat log.txt
-bash: lst: command not found
dump.rdb
geek
hello.sh
logs
log.txt
redis.conf
store
-
命令 >> 文件 2>&1
以追加的方式,把正解输出和错误输出都保存到同一文件中。 -
命令 &> 文件
以覆盖的方式,把正解输出和错误输出都保存到同一文件中。 -
命令 &>> 文件
以追加的方式,把正解输出和错误输出都保存到同一文件中。 -
命令 >> 文件1 2>> 文件 2
把正解的输出追加到文件 1 中,把错误的输出追加到文件 2 中。
通配符与其它特殊符号。
输入重定向。
wc [选项] [文件名]
-c 统计字节数
-w 统计单词数
-l 统计行数
- 命令 < 文件
把文件作为命令的输入。
[geek@localhost ~]$ wc < hello.sh
5 17 116
多命令顺序执行与管道符。
多命令执行符 | 格式 | 作用 |
---|---|---|
; | 命令 1; 命令 2 | 多个命令顺序执行,命令之间没有任何逻辑联系。 |
&& | 命令 1 && 命令 2 | 逻辑与 当命令 1 正确执行,命令 2 才会执行。 当命令 1 执行不正确,命令 2 不会执行。 |
|| | 命令 1 || 命令 2 | 逻辑或 当命令 1 执行不正确,命令 2 才会执行。 当命令 1 正确执行,命令 2 不会执行。 |
[geek@localhost ~]$ ls; date
dump.rdb geek hello.sh logs log.txt redis.conf store
Fri Mar 10 02:23:05 CST 2023
$ dd if=输入文件 of=输出文件 bs=字节数 count=个数
- if=输入文件
指定源文件或源设备。- of=输出文件
指定目标文件或目标设备。- bs=字节数
指定一次输入/输出多少字节,即把这些字节看成一个数据块。- count=个数
指定输入/输出多少个数据块。
[geek@localhost ~]$ date; dd if=/dev/zero of=/home/geek/testfile bs=1k count=100000; date
Fri Mar 10 02:34:12 CST 2023
100000+0 records in
100000+0 records out
102400000 bytes (102 MB) copied, 0.588161 s, 174 MB/s
Fri Mar 10 02:34:12 CST 2023
./configure && make && make install
命令 && echo yes || echo no
管道符。
命令 1 | 命令 2
命令 1 的正确输出作为命令 2 的操作对象。
ll -a /etc/ | more
netstat -an | grep “ESTABLISHED”
grep -inv “搜索内容” 文件名
-i ~ 忽略大小写。
-n ~ 输出行号。
-v ~ 反向查找。
–color=auto 搜索出的关键字用颜色表示。
[geek@localhost ~]$ netstat -an | grep ESTABLISHED
tcp 0 36 192.168.142.161:22 192.168.142.1:64528 ESTABLISHED
[geek@localhost ~]$ netstat -an | grep -n --color=auto ESTABLISHED
4:tcp 0 36 192.168.142.161:22 192.168.142.1:64528 ESTABLISHED
[geek@localhost ~]$ netstat -an | grep -n --color=auto ESTABLISHED -A 10
4:tcp 0 36 192.168.142.161:22 192.168.142.1:64528 ESTABLISHED
5-tcp6 0 0 :::22 :::* LISTEN
6-tcp6 0 0 :::3306 :::* LISTEN
7-udp 0 0 127.0.0.1:323 0.0.0.0:*
8-udp 0 0 0.0.0.0:68 0.0.0.0:*
9-udp6 0 0 ::1:323 :::*
10-raw6 0 0 :::58 :::* 7
11-Active UNIX domain sockets (servers and established)
12-Proto RefCnt Flags Type State I-Node Path
13-unix 3 [ ] DGRAM 8977 /run/systemd/notify
14-unix 2 [ ] DGRAM 8979 /run/systemd/cgroups-agent
[geek@localhost ~]$ netstat -an | grep -n --color=auto ESTABLISHED -B 10
1-Active Internet connections (servers and established)
2-Proto Recv-Q Send-Q Local Address Foreign Address State
3-tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
4:tcp 0 36 192.168.142.161:22 192.168.142.1:64528 ESTABLISHED
[geek@localhost ~]$ netstat -an | grep -n --color=auto ESTABLISHED -C 10
1-Active Internet connections (servers and established)
2-Proto Recv-Q Send-Q Local Address Foreign Address State
3-tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
4:tcp 0 36 192.168.142.161:22 192.168.142.1:64528 ESTABLISHED
5-tcp6 0 0 :::22 :::* LISTEN
6-tcp6 0 0 :::3306 :::* LISTEN
7-udp 0 0 127.0.0.1:323 0.0.0.0:*
8-udp 0 0 0.0.0.0:68 0.0.0.0:*
9-udp6 0 0 ::1:323 :::*
10-raw6 0 0 :::58 :::* 7
11-Active UNIX domain sockets (servers and established)
12-Proto RefCnt Flags Type State I-Node Path
13-unix 3 [ ] DGRAM 8977 /run/systemd/notify
14-unix 2 [ ] DGRAM 8979 /run/systemd/cgroups-agent
通配置符与其他特殊符号。
通配符。
通配符 | 作用 |
---|---|
? | 匹配一个任意字符。 |
* | 匹配 0 个或任意多个任意字符,也就是可以匹配任何内容。 |
[] | 匹配中括号中任意一个字符。例如:[abc] 代表一定匹配一个字符,或者是 a,或者是 b,或者是 c。 |
[-] | 匹配中括号中任意一个字符,- 代表一个范围。例如 [a-z] 代表匹配一个小写字母。 |
[^] | 逻辑非,表示匹配不是中括号内的一个字符。例如:[^0-9] 代表匹配一个不是数字的字符。 |
[geek@localhost test]$ touch abc
[geek@localhost test]$ touch abcd
[geek@localhost test]$ touch 012
[geek@localhost test]$ touch 0abc
[geek@localhost test]$ ls ?abc
0abc
[geek@localhost test]$ ls [0-9]*
012 0abc
[geek@localhost test]$ ls [^0-9]*
abc abcd
Bash 中其他特殊符号。
符号 | 作用 |
---|---|
‘’ | 单引号。在单引号中所有的特殊字符,如“$”和 `(反引号)都没有特殊含义。 |
“” | 双引号。在双引号中特殊符号都没有特殊含义,但是 $、` 和 \ 是例外,拥有“调用变量的值”、“引用命令”、和“转义符”的特殊含义。 |
` | 反引号。反引号括起来的内容是系统命令,在 Bash 中会先执行它。和 $() 作用一样,不过推荐使用 $(),因为反引号容易看错。 |
$() | 和反引号作用一样,用来引用系统命令。 |
# | 在 Shell 脚本中,# 开头的行代表注释。 |
$ | 用于调用变量的值,如需要调用变量 name 的值时,需要用 $name 的方式得到变量的值。 |
\ | 转义符。跟在 \ 之后的特殊符号将失去特殊含义,变成普通字符。如 \$ 将输出 $ 符号,而不当做是变量引用。 |
单引号与双引号。
[geek@localhost ~]$ name=geek
[geek@localhost ~]$ echo '$name'
$name
[geek@localhost ~]$ echo "$name"
geek
[geek@localhost ~]$ echo '$(date)'
$(date)
[geek@localhost ~]$ echo "$(date)"
Fri Mar 10 04:20:17 CST 2023
[geek@localhost ~]$ echo "\$(date)"
$(date)
反引号与 $()
[geek@localhost ~]$ echo `ls`
geek
[geek@localhost ~]$ echo $(date)
Fri Mar 10 04:21:03 CST 2023
[geek@localhost ~]$ echo "$(date)"
Fri Mar 10 04:21:14 CST 2023
Bash 的变量。
用户自定义变量。
什么是变量。
变量是计算机内存的单元,其中存放的值可以改变。当 Shell 脚本需要保存一些信息时,入一个文件名或一个数字,就把它存放在一个变量中。每个变量有一个名字,所以很用以引用它。使用变量可以保存有用信息,是系统获知用户相关设置,变量也可以用于保存暂时信息。
变量设置规则。
-
变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name”则是错误的。
-
在 Bash 中,变量的默认类型都是字符串型,如果要进行数值计算,则必需修改指定变量类型为数值型。
-
变量用等号连接值,等号左右两侧不能有空格。
-
变量的值如果有空格,需要使用单引号或双引号包括。
-
在变量的值中,可以使用
\
转义符。 -
如果需要增加变量的值,那么可以进行变量值的叠加,不过变量需要用双引号包括
$变量名
或用${变量名}
包含。 -
如果是把命令的结果作为变量值赋予变量,则需要使用反引号 ` 或 $() 包含命令。
-
环境变量名建议大写,便于区分。
变量分类。
-
用户自定义变量。
-
环境变量:这种变量中主要保存的是和系统操作环境相关的数据。
-
位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
-
预定义变量:是 Bash 中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
本地变量。
变量定义
[geek@localhost ~]$ name=geek
- 变量叠加。
[geek@localhost ~]$ aa=123
[geek@localhost ~]$ aa="$aa"456
[geek@localhost ~]$ echo $aa
123456
[geek@localhost ~]$ aa=${aa}789
[geek@localhost ~]$ echo $aa
123456789
- 变量调用。
echo $name
- 变量查看。
[geek@localhost ~]$ set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(2)-release'
COLUMNS=155
DIRSTACK=()
EUID=1000
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/home/geek/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/home/geek
HOSTNAME=localhost.localdomain
HOSTTYPE=x86_64
ID=1000
IFS=$' \t\n'
JAVA_HOME=/home/geek/geek/tools_my/jdk1.8.0_241
LANG=en_US.UTF-8
LESSOPEN='||/usr/bin/lesspipe.sh %s'
LINES=33
LOGNAME=geek
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:'
MACHTYPE=x86_64-redhat-linux-gnu
MAIL=/var/spool/mail/geek
MAILCHECK=60
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/home/geek/geek/tools_my/jdk1.8.0_241/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/geek/.local/bin:/home/geek/bin
PIPESTATUS=([0]="0")
PPID=1390
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
PS1='[\u@\h \W]\$ '
PS2='> '
PS4='+ '
PWD=/home/geek
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
SELINUX_USE_CURRENT_RANGE=
SHELL=/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
SHLVL=1
SSH_CLIENT='192.168.142.1 64528 22'
SSH_CONNECTION='192.168.142.1 64528 192.168.142.161 22'
SSH_TTY=/dev/pts/0
TERM=xterm
UID=1000
USER=geek
XDG_RUNTIME_DIR=/run/user/1000
XDG_SESSION_ID=3
_=echo
aa=
colors=/home/geek/.dircolors
name=geek
_rabbitmqctl_complete ()
{
if [ -x /usr/lib/rabbitmq/bin/rabbitmqctl ]; then
COMPREPLY=();
local LANG=en_US.UTF-8;
local word="${COMP_WORDS[COMP_CWORD]}";
local completions="$(export LANG=en_US.UTF-8; export LC_CTYPE=en_US.UTF-8; /usr/lib/rabbitmq/bin/rabbitmqctl --auto-complete $COMP_LINE)";
COMPREPLY=($(compgen -W "$completions" -- "$word"));
fi
}
[geek@localhost ~]$
- 变量删除。
[geek@localhost ~]$ unset aa
[geek@localhost ~]$ echo $aa
环境变量。
环境变量是什么。
用户自定义变量只在当前的 Shell 中生效,而环境变量会在当前 Shell 和这个 Shell 的所有子 Shell 当中生效。如果把环境变量写入相应的配置文件,那么这个环境变量就会在所有的 Shell 中生效。
设置环境变量。
- export 变量名=变量值
申明环境变量。- env
查询环境变量。- unset 变量名
删除环境变量。
[geek@localhost ~]$ pstree
-bash: pstree: command not found
[geek@localhost ~]$ sudo yum install psmisc
[geek@localhost ~]$ pstree
systemd─┬─NetworkManager─┬─dhclient
│ └─2*[{NetworkManager}]
├─agetty
├─chronyd
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─lvmetad
├─mysqld───26*[{mysqld}]
├─polkitd───6*[{polkitd}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd───sshd───sshd───bash───pstree
├─systemd-journal
├─systemd-logind
├─systemd-udevd
└─tuned───4*[{tuned}]
[geek@localhost ~]$ sh
sh-4.2$ pstree
systemd─┬─NetworkManager─┬─dhclient
│ └─2*[{NetworkManager}]
├─agetty
├─chronyd
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─lvmetad
├─mysqld───26*[{mysqld}]
├─polkitd───6*[{polkitd}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd───sshd───sshd───bash───sh───pstree
├─systemd-journal
├─systemd-logind
├─systemd-udevd
└─tuned───4*[{tuned}]
sh-4.2$ exit
exit
[geek@localhost ~]$
系统常见环境变量。
- PATH:系统查找命令的路径。
[geek@localhost ~]$ echo $PATH
/home/geek/geek/tools_my/jdk1.8.0_241/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/geek/.local/bin:/home/geek/bin
$ PATH="$PATH":/root/sh
# PATH 变量叠加。
- PS1:定义系统提示符的变量。
[geek@localhost ~]$ echo $PS1
[\u@\h \W]\$
\d
显示日期,格式为“星期 月 日”。
\h
显示简写主机名。如默认主机名为 “localhost”。
\t
显示 24 小时制时间,格式为“HH:MM:SS”。
\T
显示 12 小时制时间,格式为“HH:MM”。
\A
显示 24 小时制时间,格式为“HH:MM”。
\u
显示当前用户名。
\w
显示当前所在目录的完整名称。
\W
显示当前所在目录的最后一个目录。
执行的第几个命令。
$
提示符。如果是 root 用户会显示提示符为“#”,如果是普通用户会显示提示符为“$”。
$ PS1=’[\u@\t \W]\$ ’
$ PS1=’[\u@\@ \h \# \W]\$ ’
$ PS1=’[\u$\h \W]\$’
位置参数变量。
符号 | 作用 |
---|---|
$n | n 位数字,$0 代表命令本身,$1 ~ $9 代表第 1 到第 9 个参数,10 以上的参数需要用大括号包含,如 ${10}。 |
$* | 这个变量代表命令行中所用参数,$* 把所有的参数看成一个整体。 |
$@ | 这个变量也代表命令行中所有参数,不过 $@ 把每个参数区别对待。 |
$# | 这个变量代表命令行中所有参数的个数。 |
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
[geek@localhost geek]$ ./args1.sh
./args1.sh
[geek@localhost geek]$ ./args1.sh 1 2 3
./args1.sh
1
2
3
[geek@localhost geek]$ ./args1.sh 1 2 3 4
./args1.sh
1
2
3
#!/bin/bash
num1=$1
num2=$2
sum=$(($num1+$num2))
echo $sum
#!/bin/bash
echo “A total of $# parameters” # 使用 $# 代表所有参数的个数。
echo “The parameters is:$*” # 使用 $* 代表所有的参数。
echo “The parameters is $@” # 使用 $@ 也代表所有参数。
[geek@localhost geek]$ chmod +x args.sh
[geek@localhost geek]$ ./args.sh
“A total of 0 parameters”
“The parameters is:”
“The parameters is ”
[geek@localhost geek]$ ./args.sh 11 22 33 44 55 66
“A total of 6 parameters”
“The parameters is:11 22 33 44 55 66”
“The parameters is 11 22 33 44 55 66”
$* 和 $@ 的区别。
#!/bin/bash
for i in "$*"
# $* 中的所有参数看成一个整体,所以这个 for 循环只循环一次。
do
echo "The parameters are: $i"
done
x=1
for y in “$@”
# $@ 中每个参数看成是独立的,所以“$@”有几个参数,就循环几次。
do
echo "The parameter$x is: $y"
x=$(($x + 1))
done
[geek@localhost geek]$ vim argss.sh
[geek@localhost geek]$ chmod +x argss.sh
[geek@localhost geek]$ ./argss.sh
The parameters are:
The parameter1 is: “”
[geek@localhost geek]$ ./argss.sh 11 22 33 44 55
The parameters are: 11 22 33 44 55
The parameter1 is: “11
The parameter2 is: 22
The parameter3 is: 33
The parameter4 is: 44
The parameter5 is: 55”
预定义变量。
预定义变量。
- $?
最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一个命令正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己决定),则证明上一个命令执行不正确。
[geek@localhost geek]$ ls
args1.sh
[geek@localhost geek]$ echo $?
0
[geek@localhost geek]$ lsa
-bash: lsa: command not found
[geek@localhost geek]$ echo $?
127
-
$$
当前进程的进程号(PID)。 -
$!
后台运行的最后一个进程的进程号(PID)。
#!/bin/bash
# Author: geek(Email: YifanLiGeek@gmail.com)
# 输出当前进程的 PID。这个 PID 就是 variable.sh 这个脚本执行的,生成的进程的 PID。
echo "The current process pid is $$"
# 使用 find 命令在 root 目录下查找 hello.sh 文件。符号 & 的意思是把命令放入后台执行,工作管理我们在系统管理章节会详细介绍。
find /root -name hello.sh &
echo "The last daemon process is $!"
[geek@localhost geek]$ vim pid.sh
[geek@localhost geek]$ chmod +x pid.sh
[geek@localhost geek]$ ./pid.sh
The current process pid is 1625
The last daemon process is 1626
[geek@localhost geek]$ find: ‘/root’: Permission denied
接收键盘输入。
$ read -ptns [变量名]
- -p “提示信息”
在等待 read 输入时,输出提示信息。- -t 秒数
read 命令会一直等待用户输入,使用此选项可以指定等待时间。- -n 字符数
read 命令只接受指定的字符数,就会执行。- -s
隐藏输入的数据,适用于机密信息的输入。
#!/bin/bash
# Author: geek(Email: YifanLiGeek@gmail.com)
# 提示“请输入姓名”,并等待 30 秒,把用户的输入保存到变量 name 中。
read -t 30 -p "Please input your name: " name
echo "name is $name."
# 年龄是隐私,用 “-s” 选项隐藏输入。
read -s -t 30 -p "Please input your age: " age
echo "age is $age"
# 使用 -n 1 选项只接受一个字符就会执行(不用输入回车)。
read -n 1 -t 30 -p "Please input your gender[M/F]: " gender
echo -e "\n"
echo "sex is $gender"
[geek@localhost geek]$ vim input.sh
[geek@localhost geek]$ chmod +x input.sh
[geek@localhost geek]$ ./input.sh
Please input your name: geek
name is geek.
Please input your age: age is 3
Please input your gender[M/F]: m
sex is m
[geek@localhost geek]$
Bash 的运算符。
数值运算与运算符。
[geek@localhost geek]$ aa=11
[geek@localhost geek]$ bb=22
[geek@localhost geek]$ cc=$aa+$bb
[geek@localhost geek]$ echo $cc
11+22
declare 声明变量类型。
$ declare [+/-] [选项] 变量名
-
给变量设定类型属性。+
取消变量的类型属性。- -i
将变量声明为整数型(integer)。- -x
将变量声明为环境变量。- -p
显示指定变量的被声明的类型。
[geek@localhost geek]$ declare -p aa
declare -- aa="11"
[geek@localhost geek]$ export aa
[geek@localhost geek]$ declare -p aa
declare -x aa="11"
[geek@localhost geek]$ declare -i cc=$aa+$bb
[geek@localhost geek]$ echo $cc
33
数值运算 ~ 方法 1。
# 给变量 aa 和 bb 赋值。
aa=11
bb=22
[geek@localhost geek]$ declare -i cc=$aa+$bb
[geek@localhost geek]$ echo $cc
33
方法 2 ~ expr 或 let 数值运算工具。
# 给变量 aa 和 bb 赋值。
aa=11
bb=22
dd=$(expr $aa + $bb)
# dd 的值是 aa 和 bb 的和。注意 “+” 号左右两侧必须有空格。
[geek@localhost geek]$ dd=$(expr $aa + $bb)
[geek@localhost geek]$ echo $dd
33
方法 3 ~ $((运算式)) 或 $[运算式] ~ 推荐使用!!
单括号 ~ 系统命令。
aa=11
bb=22
[geek@localhost geek]$ ff=$(($aa + $bb))
[geek@localhost geek]$ echo $ff
33
[geek@localhost geek]$ gg=$[$aa + $bb]
[geek@localhost geek]$ echo $gg
33
运算符。
优先级 | 运算符 | 说明 |
---|---|---|
13 | -,+ | 单目负、单目正。 |
12 | !,~ | 逻辑非、按位取反或补码。 |
11 | *,/,% | 乘、除、取模。 |
10 | +,- | 加、减。 |
9 | << , >> | 按位左移、按位右移。 |
8 | <=, >=, <, > | 大于或小于、大于或等于、小于、大于。 |
7 | ==, != | 等于、不等于。 |
6 | & | 按位与。 |
5 | ^ | 按位异或。 |
4 | | | 按位或。 |
3 | && | 逻辑与。 |
4 | | | 逻辑或。 |
3 | =, +=, -=,*-,/=,%=,&=,^=, |=, <<=, >>= | 赋值、运算且赋值。 |
[geek@localhost geek]$ aa=$(( (11+3)*3/2 ))
[geek@localhost geek]$ echo $aa
21
# 虽然乘和除的优先级高于加,单数通过小括号可以调整运算优先级。
[geek@localhost geek]$ bb=$((14%3))
[geek@localhost geek]$ echo $bb
2
# 14 不能被 3 整除,余数是 2。
[geek@localhost geek]$ cc=$((1&&0))
[geek@localhost geek]$ echo $cc
0
# 逻辑与运算只有想与的两边都是 1,与的结果才是 1,否则与的结果是 0。
变量测试与内容替换。
变量置换方式 | 变量 y 没有设置 | 变量 y 为空值 | 变量 y 设置值 |
---|---|---|---|
x=${y-新值} | x=新值 | x 为空 | x=$y |
x=${y:-新值} | x=新值 | x=新值 | x=$y |
x=${y+新值} | x 为空 | x=新值 | x=新值 |
x=${y:+新值} | x 为空 | x 为空 | x=新值 |
x=${y=新值} | x=新值 y=新值 | x 为空 y 值不变 | x=$y y 值不变 |
x=${y:=新值} | x=新值 y=新值 | x=新值 y=新值 | x=$y y 值不变 |
x=${y?新值} | 新值输入到标准错误输出(就是屏幕) | x 为空 | x=$y |
x=${y:?新值} | 新值输出到标准错误输出 | 新值输出到标准错误输出 | x=$y |
环境变量配置文件。
环境变量配置文件简介。
source 命令。
使配置文件立即生效。
source 配置文件
或
. 配置文件
环境变量配置文件简介。
环境变量配置文件中主要是定义对系统的操作环境生效的系统默认环境变量,比如 PATH、HISTSIZE、PS1、HOSTNAME 等默认环境变量。
-
/etc/profile
-
/etc/profiled.d/*.sh
-
~/.bash_profile
-
~/.bashrc
-
/etc/bashrc
环境变量配置文件作用。
以下几个环境变量的配置文件是最主要的。
/etc/profile
/etc/profile.d/*.sh 指 /etc/profile.d/ 下所有的 .sh 结尾的文件。
~/.bash_profile
~/.bashrc
/etc/bashrc
环境变量配置文件调用顺序流程图。
这些是在用户登陆的时候挨个调用,所以在这里面设置环境变量,登陆之后就会自动设置好。
- 登陆输入密码之后,第一步是读取 /etc/profile 文件。
/etc/profile 的作用。
USER 变量
LOGNAME 变量
MAIL 变量
PATH 变量
HOSTNAME 变量
HISTSIZE 变量
umask
调用 /etc/profile.d/*.sh 文件。
-
接下来便调用 /etc/profile.d/*.sh 文件。
然后就是下面的文件,语言包文件,识别系统自带的语言。 -
~/.bash_profile 的作用。
调用了 ~/.bashrc 文件。
在 PATH 变量后面加入了 “:$HOME/bin” 这个目录。
[geek@localhost ~]$ cat ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
- ~/.bashrc 的作用。
定义默认别名。
调用 /etc/bashrc。
[geek@localhost ~]$ cat ~/.bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
- /etc/bashrc 的作用。
PS1 变量。
umask。
PATH 变量。
调用 /etc/profile.d/*.sh 文件。
(# We’re not a login shell)
[geek@localhost ~]$ cat /etc/bashrc
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
# are we an interactive shell?
if [ "$PS1" ]; then
if [ -z "$PROMPT_COMMAND" ]; then
case $TERM in
xterm*|vte*)
if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
elif [ "${VTE_VERSION:-0}" -ge 3405 ]; then
PROMPT_COMMAND="__vte_prompt_command"
else
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
fi
;;
screen*)
if [ -e /etc/sysconfig/bash-prompt-screen ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
else
PROMPT_COMMAND='printf "\033k%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
fi
;;
*)
[ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default
;;
esac
fi
# Turn on parallel history
shopt -s histappend
history -a
# Turn on checkwinsize
shopt -s checkwinsize
[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
# You might want to have e.g. tty in prompt (e.g. more virtual machines)
# and console windows
# If you want to do so, just add e.g.
# if [ "$PS1" ]; then
# PS1="[\u@\h:\l \W]\\$ "
# fi
# to your custom modification shell script in /etc/profile.d/ directory
fi
if ! shopt -q login_shell ; then # We're not a login shell
# Need to redefine pathmunge, it get's undefined at the end of /etc/profile
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}
# By default, we want umask to get set. This sets it for non-login shell.
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
umask 002
else
umask 022
fi
SHELL=/bin/bash
# Only display echos from profile.d scripts if we are no login shell
# and interactive - otherwise just process them to set envvars
for i in /etc/profile.d/*.sh; do
if [ -r "$i" ]; then
if [ "$PS1" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done
unset i
unset -f pathmunge
fi
# vim:ts=4:sw=4
这一块就是进入界面以内,切换 shell 登陆方式,这种不需要密码,所以和前面的 /etc/profile 的作用不冲突。
其他配置文件和登录信息。
注销时生效的环境变量配置文件。
- ~/.bash_logout。
注销登陆时写入。
[geek@localhost ~]$ cat ~/.bash_logout
# ~/.bash_logout
其他配置文件。
-
~/bash_history
历史命令文件。 -
Shell 登录信息。
本地终端欢迎信息:/etc/issue。
[geek@localhost ~]$ cat /etc/issue
\S
Kernel \r on an \m
转义符 | 作用 |
---|---|
\d | 显示当前系统日期。 |
\s | 显示操作系统名称。 |
\l | 显示登录的终端号,这个比较常用。 |
\m | 显示硬件体系结构,如 i386、i686 等。 |
\n | 显示主机名。 |
\o | 显示域名。 |
\r | 显示内核版本。 |
\t | 显示当前系统时间。 |
\u | 显示当前登录用户的序列号。 |
远程终端欢迎信息:/etc/issue.net。
[geek@localhost ~]$ cat /etc/issue.net
\S
Kernel \r on an \m
-
转义符在 /etc/issue.net 文件中不能使用。
-
是否显示此欢迎信息,由 ssh 的配置文件 /etc/ssh/sshd_config 决定,加入 “Banner /etc/issue.net” 行才能显示(记得重启 SSH 服务)。
[geek@localhost ~]$ sudo cat /etc/ssh/sshd_config
[sudo] password for geek:
# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
PasswordAuthentication yes
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
#KerberosUseKuserok yes
# GSSAPI options
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
#GSSAPIEnablek5users no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux and may cause several
# problems.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ShowPatchLevel no
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
# override default of no subsystems
Subsystem sftp /usr/libexec/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
登陆后欢迎信息:/etc/motd。
不管是本地登录,还是远程登录,都可以显示此欢迎信息。
Shell 编程。
基础正则表达式。
正则表达式与通配符。
正则表达式用来在文件中匹配符合条件的字符串
,正则是包含匹配
。grep、awk、 sed 等命令可以支持正则表达式。
通配符用来匹配符合条件的文件名
,通配符是完全匹配
。ls、find、cp 这些命令不支持正则表达式,所以只能使用 shell 自己的通配符来进行匹配了。
基础正则表达式。
元字符。 | 作用。 |
---|---|
* | 前一个字符匹配0次或任意多次。 |
. | 匹配除了换行符外任意一个字符。 |
^ | 匹配行首。eg. ^hello 会匹配以 hello 开头的行。 |
$ | 匹配行尾。eg. hello& 会匹配以 hello 结尾的行。 |
[] | 匹配中括号中指定的任意一个字符,只匹配一个字符。eg. [aoeiu] 匹配任意一个元音字母,[0-9] 匹配任意一位 数字,[a-z][0-9] 匹配小写字和一位数字构成的两位字符。 |
[^] | 匹配除中括号的字符以外的任意一个字符。eg. [^0-9] 匹配任意一位非数字字符,[^a-z] 表示任意一位非小写字母。 |
\ | 转义符。用于取消讲特殊符号的含义取消。 |
\{n\} | 表示其前面的字符恰好出现 n 次。eg. [0-9]\{4\} 匹配 4 位数字,[1][3-8][0-9]\{9\} 匹配手机号码。 |
{n,} | 表示其前面的字符出现不小于 n 次。eg. [0-9]{2,} 表示两位及以上的数字。 |
{n,m} | 表示其前面的字符至少出现 n 次,最多出现 m 次。eg. [a- z]{6,8} 匹配 6 到 8 位的小写字母。 |
- * 前一个字符匹配 0 次,或任意多次。
grep “a*” test_rule.txt
匹配所有内容,包括空白行。
grep “aa*” test_rule.txt
匹配至少包含有一个 a 的行。
grep “aaa*” test_rule.txt
匹配最少包含两个连续 a 的字符串。
grep “aaaaa*” test_rule.txt
则会匹配最少包含四个个连续 a 的字符串。
- . 匹配除了换行符外任意一个字符。
grep “s…d” test_rule.txt
“s…d” 会匹配在 s 和 d 这两个字母之间一定有两个字符的单词。
grep “s.*d” test_rule.txt
匹配在 s 和 d 字母之间有任意字符。
grep “.*” test_rule.txt
匹配所有内容。
^
匹配行首,$
匹配行尾。
grep “^M” test_rule.txt
匹配以大写 M 开头的行。
grep “n$” test_rule.txt
匹配以小写 n 结尾的行。
grep -n “^$” test_rule.txt
匹配空白行。
- “[]” 匹配中括号中指定的任意一个字符,只匹配一个字符。
grep "s[ao]id” test_rule.txt
匹配 s 和 i 字母中,要么是 a、要么是 o。
grep “[0-9]” test_rule.txt
匹配任意一个数字。
grep “^[a-z]” test_rule.txt
匹配用小写字母开头的行。
- “[^]” 匹配除中括号的字符以外的任意一个字符。
grep "^[^a-z]” test_rule.txt
匹配不用小写字母开头的行。
grep “^[^a-z A-Z]” test_rule.txt
匹配不用字母开头的行。
- “” 转义符。
grep “\.$” test_rule.txt
匹配使用 “.” 结尾的行。
- “\{n\}” 表示其前面的字符恰好出现 n 次。
grep “a\{3\}” test_rule.txt
匹配 a 字母连续出现三次的字符串。
grep “[0-9]\{3\}” test_rule.txt
匹配包含连续的三个数字的字符串。
- “\{n,\}” 表示其前面的字符出现不小于 n 次。
grep “^[0-9]\{3,\}[a-z]” test_rule.txt
匹配最少用连续三个数字开头的行。
- “\{n,m\}” 匹配其前面的字符至少出现 n 次,最多出现 m 次。
grep “sa\{1,3\}i” test_rule.txt
匹配在字母 s 和字母 i 之间有最少一个 a,最多三个 a。
字符截取命令。
cut 字段提取命令。
cut [选项] 文件名
-f ~ 列号:提取第几列。
-d ~ 分隔符:按照指定分隔符分割列。
grep 为提取行,cut 提取列,而且 cut 提取的表格中,只能用制表符隔开不能用空格比如。
[geek@localhost geek]$ cat student.txt
ID Name Gender Mark
1 Li M 86
2 Shen M 90
3 Gao M 83
他们之间所有的都是拿 Tab 键隔开的,不是空格。
提取多列时,用 ,
隔开就可以。
[geek@localhost geek]$ cut -f 2 student.txt
Name
Li
Shen
Gao
[geek@localhost geek]$ cut -f 2,3 student.txt
Name Gender
Li M
Shen M
Gao M
有具体分割符时,也可以没有 Tab 键。
# 以 : 为分隔符取 1,3 列。
[geek@localhost geek]$ cut -d ":" -f 1,3 /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-network:192
dbus:81
polkitd:999
sshd:74
postfix:89
chrony:998
geek:1000
mysql:27
rabbitmq:997
ntp:38
一般在使用 cut 命令的时候和管道符“|”连着使用。
[geek@localhost geek]$ cat /etc/passwd | grep /bin/bash
root:x:0:0:root:/root:/bin/bash
geek:x:1000:1000:geek:/home/geek:/bin/bash
[geek@localhost geek]$ cat /etc/passwd | grep /bin/bash | grep -v root
geek:x:1000:1000:geek:/home/geek:/bin/bash
[geek@localhost geek]$ cat /etc/passwd | grep /bin/bash | grep -v root | cut -d ":" -f 1
geek
printf 命令。
printf “~输出类型~ ~输出格式~” 输出内容
输出类型。
-
%ns。
输出字符串。n 是数字指代输出几个字符。 -
%ni。
输出整数。n 是数字指代输出几个数字。 -
%m.nf。
输出浮点数。m 和 n 是数字,指代输出的整数位数和小数位数。如 %8.2f 代表共输出 8 位数,其中 2 位是小数,6 位是整数。
输出格式。
-
\a。
输出警告声音。 -
\b。
输出退格键,也就是 Backspace 键。 -
\f。
清除屏幕。 -
\n。
换行。 -
\r。
回车,也就是 Enter 键。 -
\t。
水平输出退格键,也就是 Tab 键。 -
\v。
垂直输出退格键,也就是 Tab 键。
eg.。
# 一个字符串。
[geek@localhost geek]$ printf %s 1 2 3 4 5 6
123456
# 将第一个 %s 后(%s %s 1 2 3 4 5 6)当做一整个字符串。
[geek@localhost geek]$ printf %s %s %s 1 2 3 4 5 6
%s%s123456
[geek@localhost geek]$ printf '%s %s %s' 1 2 3 4 5 6
1 2 34 5 6
[geek@localhost geek]$ printf '%s %s %s\n' 1 2 3 4 5 6
1 2 3
4 5 6
只有最后一个会输出。
1 2 3
4 5 6
因为每有一个 %s 代表每几个字符输出一次。
%s %s %s\n 代表每三个字符输出一次并且换行。
他在与 cat 命令结合使用的时候,需要用 $() 把 cat 命令括起来,使用这种命令赋予变量的方式,才能正确输出文件内容,但是具体格式还得用 %s\t 或者 %s\n 控制。
[geek@localhost geek]$ printf '%s' student.txt
student.txt[geek@localhost geek]$ cat student.txt | printf '%s'
[geek@localhost geek]$ printf '%s' $(cat student.txt)
IDNameGenderMark1LiM862ShenM903GaoM83[geek@localhost geek]$
- printf 主要在 awk 命令编程中使用。
eg.。
vim student.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
# 不调整输出格式。
[geek@localhost geek]$ printf '%s' $(cat student.txt)
IDNameGenderMark1LiM862ShenM903GaoM83[geek@localhost geek]$
# 调整格式输出。
[geek@localhost geek]$ printf '%s\t %s\t %s\t %s\t\n' $(cat student.txt)
ID Name Gender Mark
1 Li M 86
2 Shen M 90
3 Gao M 83
在 awk 命令的输出中支持 print 和 printf 命令。
-
print。
print 会在每个输出之后自动加入一个换行符(Linux 默认没有 print 命令)。 -
printf。
printf 是标准格式输出命令,并不会自动加入换行符,如果需要换行,需要手工加入换行符。
awk 命令。
awk 命令也叫 awk 编程,可以识别非制表符的空格,用来解决 cut 命令解决不了的提取列工作,他是把需要提取的原文件一行一行扫描,扫描每一行中所需要点列,然后把它记录下来,在全部扫描完之后全部打印出来。
- awk “条件 1 {动作 1} 条件 2 {动作 2} …” 文件名
条件(Pattern)。
一般使用关系表达式作为条件。
x > 10 判断变量 x 是否大于 10
x >= 10 大于等于
x <= 10 小于等于
动作(Action)。
格式化输出。
流程控制语句。
eg.。
vim student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ awk '{printf $2 "\t" $6"\n"}' student1.txt
Name Average
Liming 87.66
Sc 85.66
Gao 91.66
其中 $2 代表第 2 列,$6 代表第 6 列,他可以识别非制表符的空格,单引号里面直接大括号代表没有条件,只要是输入有内容全部符合。
取第 2 列和第 6 列。
提取 df -h 命令显示之后的内容中第一列和第三列。
[geek@localhost geek]$ df -h | awk '{print $1 "\t" $3}'
Filesystem Used
devtmpfs 0
tmpfs 0
tmpfs 7.7M
tmpfs 0
/dev/mapper/centos_192-root 15G
/dev/sda1 163M
tmpfs 0
需要注意,
printf 不可以自动换行,print 可以在末尾自动换行,但是在 Linux 系统中没有 print 命令,只有 printf 命令,但是在 wak 命令中两个都有,使用 print 可以少一个换行符。
eg. 监控分区大小。
[geek@localhost geek]$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 475M 0 475M 0% /dev
tmpfs 487M 0 487M 0% /dev/shm
tmpfs 487M 7.7M 479M 2% /run
tmpfs 487M 0 487M 0% /sys/fs/cgroup
/dev/mapper/centos_192-root 17G 15G 2.9G 84% /
/dev/sda1 1014M 163M 852M 16% /boot
tmpfs 98M 0 98M 0% /run/user/1000
[geek@localhost geek]$ df -h | grep root
/dev/mapper/centos_192-root 17G 15G 2.9G 84% /
[geek@localhost geek]$ df -h | grep root | awk '{print $5}'
84%
[geek@localhost geek]$ df -h | grep root | awk '{print $5}' | cut -d "%" -f 1
84
BEGIN。
awk “条件 1 {动作 1} 条件 2 {动作 2} …” 文件名
BEGIN 必须是大写,ta 是一个条件。
[geek@localhost geek]$ awk 'BEGIN { printf "This is a transcript.\n" } {printf $2 "\t" $6 "\n"}' student1.txt
This is a transcript.
Name Average
Liming 87.66
Sc 85.66
Gao 91.66
他会在打印出 2,6 行之前先输出一句话 This is a transcript
它的作用是强者命令第一个执行他后面的语句,也可以指定分割符。
FS 内置变量 & BEGIN & END。
FS 是用来指定分隔符的。
FS=“:” 就是指定 : 为分隔符。
eg.。
[geek@localhost geek]$ awk '{FS=":"} {printf $1 "\t" $3 "\n"}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
sshd 74
postfix 89
chrony 998
geek 1000
mysql 27
rabbitmq 997
ntp 38
cat /etc/passwd | grep “/bin/bash” | awk ‘BEGIN {FS=“:”} {printf $1 “\t” $3 “\n”}’
这是打印用户信息第一和第三列,为什么需要在 {FS=“:”} 前加 BEGIN 呢?
因为如果你不加 BEGIN 你会发现除了第一行,其他都已经按格式打印出来了,但是只有第一行会照原样输出,因为 awk 默认是空格为分隔符,他在执行这条命令的时候,第一行数据已经被扫描了,所以来不及修改格式,但是加了 BEGIN,他会第一步强制先把默认分隔符修改了。
[geek@localhost geek]$ awk 'BEGIN {FS=":"} {printf $1 "\t" $3 "\n"}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
sshd 74
postfix 89
chrony 998
geek 1000
mysql 27
rabbitmq 997
ntp 38
关系运算符。
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ cat student1.txt | grep -v Name | awk '$6 >= 87 {printf $2 "\n" }'
Liming
Gao
sed 命令。
sed 是一种几乎包括在所有 UNIX 平台(包括 Linux)的轻量级流编辑器。sed 主要是用来将数据进行选取、替换、删除、新增的命令。
ta 不仅可以修改文件内容,还可以修改命令结果,支持管道符操作,这就是与 vim 最大的区别。
sed [选项] ‘[动作]’ 文件名
选项。
-
-n。
一般 sed 命令会把所有数据都输出到屏幕,如果加入此选项,则只会把经过 sed 命令处理的行输出到屏幕。 -
-e。
允许对输入数据应用多条 sed 命令编辑。 -
-i。
用 sed 的修改结果直接修改读取数据的文件,而不是由屏幕输出。
动作。
-
a。
追加,在当前行后添加一行或多行。添加多行时,除最后 一行外,每行末尾需要用 “\” 代表数据未完结。 -
c。
行替换,用 c 后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用 “\” 代表数据未完结。 -
i。
插入,在当期行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用 “\” 代表数据未完结。 -
d。
删除,删除指定的行。 -
p。
打印,输出指定的行。 -
s。
字串替换,用一个字符串替换另外一个字符串。格式为行范围s/旧字串/新字串/g
(和 vim 中的替换格式类似)。
eg.。
sed ‘2p’ student1.txt
查看文件的第二行会显示。
[geek@localhost geek]$ sed '2p' student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
会发现多了一行,因为一般 sed 命令会把所有数据都输出到屏幕,只不过会先输出你想要的,这时候就需要 -n 配合。
输入 -n 后就没有多余的了。
[geek@localhost geek]$ sed -n '2p' student1.txt
1 Liming 82 95 86 87.66
删除第二行到第四行的数据,但不修改文件本身。
[geek@localhost geek]$ sed '2,4d' student1.txt
ID Name PHP Linux MySQL Average
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
在第二行后追加 hello。
[geek@localhost geek]$ sed '2a hello' student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
hello
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
在第二行前插入两行数据。
[geek@localhost geek]$ sed '2i hello \
> world' student1.txt
ID Name PHP Linux MySQL Average
hello
world
1 Liming 82 95 86 87.66
2 Sc 99 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 99 96 87 85.66
3 Gao 99 83 93 91.66
数据替换。
[geek@localhost geek]$ sed '2c No such person' student1.txt
ID Name PHP Linux MySQL Average
No such person
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
- 字符串替换
sed ‘s/旧字串/新字串/g’ 文件名
在第三行中,把 74 换成 99。
[geek@localhost geek]$ sed '3s/74/99/g' student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 99 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
sed 操作的数据直接写入文件。
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
[geek@localhost geek]$ sed -i '3s/74/99/g' student1.txt
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 99 96 87 85.66
3 Gao 99 83 93 91.66
同时把 “Liming” 和 “Gao” 替换为空。
[geek@localhost geek]$ sed -e 's/Liming//g; s/Gao//g' student1.txt
ID Name PHP Linux MySQL Average
1 82 95 86 87.66
2 Sc 99 96 87 85.66
3 99 83 93 91.66
[geek@localhost geek]$ cat student1.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 99 96 87 85.66
3 Gao 99 83 93 91.66
字符处理命令。
排序命令 sort。
sort [选项] 文件名
-
-f。
忽略大小写 -
-n。
以数值型进行排序,默认使用字符串型排序。 -
-r。
反向排序。 -
-t。
指定分隔符,默认是分隔符是制表符。 -
-k n[,m]。
按照指定的字段范围排序。从第 n 字段开始,m 字段结束(默认到行尾)。
eg.。
sort /etc/passwd
排序用户信息文件。
sort -r /etc/passwd
反向排序。
sort -t “:” -k 3,3 /etc/passwd
指定分隔符是 “:”,用第三字段开头,第三字段结尾排序,就是只用第三字段排序,但是他不认识数字,会把数字当成字符串,认为 3 比 11 大 ,所以我需要加 -n,进行数值排序。
sort -n -t “:” -k 3,3 /etc/passwd
统计命令 wc。
wc [选项] 文件名
-
-l。
只统计行数。 -
-w。
只统计单词数。 -
-m。
只统计字符数。
条件判断。
按照文件类型进行判断。
测试选项 | 作用 |
---|---|
-b 文件 | 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)。 |
-c文件 | 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)。 |
-d 文件 | 判断该文件是否存在,并且是否为目录文件(是目录为真)。 |
-e 文件 | 判断该文件是否存在(存在为真)。 |
-f 文件 | 判断该文件是否存在,并且是否为普通文件(是普通文件为真)。 |
-L 文件 | 判断该文件是否存在,并且是否为管道文件(是管道文件为真)。 |
-p 文件 | 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)。 |
-s 文件 | 判断该文件是否存在,并且是否为非空(非空为真)。 |
-S 文件 | 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)。 |
两种判断格式。
上面的表结合一下命令来判断。
test -e /root/install.log
[ -e /root/install.log ]
中括号两边必须有空格,只能为 [ -e /root/install.log ]
,不能是 [-e /root/install.log]。
[geek@localhost geek]$ test -e loop.lua
[geek@localhost geek]$ echo $?
0
在判断之后,使用 echo $? 来观察输出语句是否为真。
[ -d /root ] && echo “yes” || echo “no”
第一个判断命令如果正确执行,则打印 “yes”,否则打印 “no”。
按照文件权限进行判断。
测试选项 | 作用 |
---|---|
-r 文件 | 判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真)。 |
-w文件 | 判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真)。 |
-x 文件 | 判断该文件是否存在,并且是否该文件拥有执行权限(有执行权限为真)。 |
-u 文件 | 判断该文件是否存在,并且是否该文件拥有 SUID 权限(有 SUID 权限为真)。 |
-g 文件 | 判断该文件是否存在,并且是否该文件拥有 SGID 权限(有 SGID 权限为真)。 |
-k 文件 | 判断该文件是否存在,并且是否该文件拥有 SBit 权限(有 SBit 权限为真)。 |
eg.。
[geek@localhost geek]$ [ -w student.txt ] && echo “yes” || echo "no"
“yes”
# 判断文件是拥有写权限的。
不过系统不会区分,比如 -w,只要所有者,所属组,其他人其中有一个有写权限,ta 就会返回 yes,所以这个时候就需要我们自己写脚本。
两个文件之间进行比较。
测试选项 | 作用 |
---|---|
文件 1 -nt 文件 2 | 判断文件 1 的修改时间是否比文件 2 的新(如果新则为真)。 |
文件 1 -ot 文件 2 | 判断文件 1 的修改时间是否比文件 2 的旧(如果旧则为真)。 |
文件 1 -ef 文件 2 | 判断文件 1 是否和文件 2 的 Inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法。 |
eg.。
# 创建一个硬链接。
[geek@localhost geek]$ ln student.txt /tmp/stu.txt
[geek@localhost geek]$ ll
-rw-rw-r--. 2 geek geek 53 Mar 10 13:11 student.txt
[geek@localhost geek]$ ll /tmp/
total 4
-rw-rw-r--. 2 geek geek 53 Mar 10 13:11 stu.txt
# 用 test 测试。
[geek@localhost geek]$ [ student.txt -ef /tmp/stu.txt ] && echo "yes" || echo "no"
yes
两个整数之间比较。
测试选项 | 作用 |
---|---|
整数 1 -eq 整数 2 | 判断整数1是否和整数2相等(相等为真)。 |
整数 1 -ne 整数 2 | 判断整数1是否和整数2不相等(不相等位置)。 |
整数 1 -gt 整数 2 | 判断整数1是否大于整数2(大于为真)。 |
整数 1 -lt 整数 2 | 判断整数1是否小于整数2(小于位置)。 |
整数 1 -ge 整数 2 | 判断整数1是否大于等于整数2(大于等于为真)。 |
整数 1 -le 整数 2 | 判断整数1是否小于等于整数2(小于等于为真)。 |
eg.。
[geek@localhost geek]$ [ 23 -ge 22 ] && echo "yes" || echo "no"
yes
# 判断 23 是否大于等于 22。
[geek@localhost geek]$ [ 23 -le 22 ] && echo "yes" || echo "no"
no
# 判断 23 是否小于等于 22。
字符串的判断。
测试选项 | 作用 |
---|---|
-z 字符串 | 判断字符串是否为空(为空返回真)。 |
-n 字符串 | 判断字符串是否为非空(非空返回真)。 |
字串 1 == 字串 2 | 判断字符串 1 是否和字符串 2 相等(相等返回真)。 |
字串 1 != 字串 2 | 判断字符串 1 是否和字符串 2 不相等(不相等返回真)。 |
eg.。
# 给 name 变量赋值。
[geek@localhost geek]$ name=geek
# 判断 name 变量是否为空,因为不为空,所以返回 no。
[geek@localhost geek]$ [ -z "$name" ] && echo "yes" || echo "no"
no
# 给变量 aa 和变量 bb 赋值。
[geek@localhost geek]$ aa=11
[geek@localhost geek]$ bb=22
[geek@localhost geek]$ [ "$aa" == "$bb" ] && echo "yes" || echo "no"
no
# 判断两个变量的值是否相等,明显不相等 ,所以返回 no。
多重条件判断。
测试选项 | 作用 |
---|---|
判断 1 -a 判断 2 | 逻辑与,判断 1 和判断 2 都成立,最终的结果才为真。 |
判断 1 -o 判断 2 | 逻辑或,判断 1 和判断 2 有一个成立,最终的结果就为真。 |
!判断 | 逻辑非,使原始的判断式取反。 |
eg.。
[geek@localhost geek]$ aa=11
[geek@localhost geek]$ [ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no"
no
# 判断变量 aa 是否有值,同时判断变量 aa 的是否大于 23。
# 因为变量 aa 的值不大于 23,所以虽然第一个判断值为真,返回的结果也是假。
[geek@localhost geek]$ aa=24
[geek@localhost geek]$ [ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no"
yes
流程控制。
if 语句。
单分支 if 条件语句。
if [ 条件判断式 ]; then
程序
fi
or
if [ 条件判断式 ]
then
程序
fi
单分支条件语句需要注意几个点。
-
if 语句使用 fi 结尾,和一般语言使用大括号结尾不同。
-
[ 条件判断式 ] 就是使用 test 命令判断,所以中括号和条件判断式之间必须有空格。
-
then 后面跟符合条件之后执行的程序,可以放在 [] 之后,用“;”分割。也可以换行写入,就不需要“;”了。
eg. 判断分区使用率。
#!/bin/bash
# Author: geek(Email: YifanLiGeek@gmail.com)
# 统计根分区使用率。
rate=$(df -h | grep "/dev/sda3" | awk '{print $5}' | cut -d "%" -f 1)
# 把根分区使用率作为变量值赋予变量 rate。
if [ $rate -ge 80 ]; then
echo "Warning! /dev/sda3 is almost full!"
fi
双分支 if 条件语句。
if [ 条件判断式 ]; then
条件成立时,执行的程序。
else
条件不成立时,执行的另一个程序。
fi
eg. 备份 MySQL 数据库。
#!/bin/bash
# 备份 MySQL 数据库。
# Author: geek(Email: YifanLiGeek@gmail.com)
# 同步系统时间。
ntpdate asia.pool.ntp.org &> /dev/null
# 把当前系统时间按照 “年月日” 格式赋予变量 date。
date=$(date +%y%m%d)
# 统计 MySQL 数据库的大小,并把大小赋予 size 变量。
size=$(du -sh /var/lib/mysql)
if [ -d /tmp/dbbak ]; then
echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
cd /tmp/dbbak || exit
tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &> /dev/null
rm -rf /tmp/dbbak/dbinfo.txt
else
mkdir /tmp/dbbak
echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
cd /tmp/dbbak || exit
tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &> /dev/null
rm -rf /tmp/dbbak/dbinfo.txt
fi
eg. 判断 Apache 是否启动。
#!/bin/bash
# Author: geek(Email: YifanLiGeek@gmail.com)
port=$(nmap -sT 192.168.12.161 | grep tcp | grep http | awk '{print $2}')
# 使用 nmap 命令扫描服务器,并截取 Apache 服务的状态,赋予变量 port。
if [ "$port" == "open" ]; then
echo "$(date) httpd is ok!" >> /tmp/autostart-acc.log
else
/etc/rc.d/init.d/httpd start &> /dev/null
echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
fi
nmap 远程扫描,检查服务是否启动。
nmap -sT 扫描指定服务器上开启的 TCP 端口。
多分支 if 条件语句。
if [ 条件判断式 1 ]; then
当条件判断式 1 成立时,执行程序 1。
elif [ 条件判断式 2 ]; then
当条件判断式 2 成立时,执行程序 2。
...省略更多条件...
else
当所有条件都不成立时,最后执行此程序。
fi
eg.。
#!/bin/bash
# 判断用户输入的是什么文件。
# Author: geek(Email: YifanLiGeek@gmail.com)
# 接收键盘的输入,并赋予变量 file。
read -p "Please input a filename: " file
# 判断 file 变量是否为空。
if [ -z "$file" ]; then
echo "Error,please input a filename"
# 定义错误返回值 1。
exit 1
# 判断 file 的值是否存在。
elif [ ! -e "$file" ]; then
echo "Your input is not a file!"
# 定义错误返回值 2。
exit 2
# 判断 file 的值是否为普通文件。
elif [ -f "$file" ]; then
echo "$file is a regular file!"
# 判断 file 的值是否为目录文件。
elif [ -d "$file" ]; then
echo "$file is a directory!"
else
echo "$file is an other file!"
fi
case 语句。
多分支 case 条件语句。
case 语句和 if…elif…else 语句一样都是多分支条件语句,不过和 if 多分支条件语句不同的是,case 语句只能判断一种条件关系,而 if 语句可以判断多种条件关系。
case $变量名 in
"值 1")
如果变量的值等于值 1,则执行程序 1。
;;
"值 2")
如果变量的值等于值 2,则执行程序 2。
;;
...省略其他分支...
*)
如果变量的值都不是以上的值,则执行此程序。
;;
esac
用于选择列表,打印选择车票。
eg.。
#!/bin/bash
# 判断用户输入。
# Author: geek(Email: YifanLiGeek@gmail.com)
read -p "Please choose yes/no: " -t 30 cho
case $cho in
"yes")
echo "Your choose is yes!"
;;
"no")
echo "Your choose is no!"
;;
*)
echo "Your choose is error!"
;;
esac
for 循环。
- 语法一。
for 变量 in 值 1 值 2 值 3
do
程序
done
eg.。
#!/bin/bash
# 打印时间。
# Author: geek(Email: YifanLiGeek@gmail.com)
for time in morning noon afternoon evening; do
echo "This time is $time!"
done
这种方法看起来很笨,需要把循环次数写入 for,但是在系统管理的时候,当我们不确定循环次数的时候,比如解压缩一个文件里所有的压缩包,ta 会自动加入新的压缩包,这个时候我就需要用这种笨办法,这种后面加次数的也有一个好处,就是循环变量只要是由空格,或者回车,或者 tab 键隔开的,都可以算在内,所以才能和 cat,ls 等命令结合使用,cat 命令执行之后显示的结果就是由回车隔开的,都可以算成是循环变量。在加入或者减少压缩包的时候,不需要修改脚本。
eg. 批量解压缩。
#!/bin/bash
# 批量解压缩软件包。
# Author: geek(Email: YifanLiGeek@gmail.com)
y=1
cd /home/geek/geek || exit
# ls *.tar.gz 输出结果覆盖到 ls.log 文件。
ls *.tar.gz > ls.log
for i in $(cat ls.log); do
echo $y
y=$(( $y + 1 ))
tar -zxf $i $ > /dev/null
done
rm -rf /lamp/ls.log
- 语法二。
for ((初始值; 循环控制条件; 变量变化)); do
程序
done
eg. 计算 1 加到 100。
#!/bin/bash
# 计算 1 加到 100。
# Author: geek(Email: YifanLiGeek@gmail.com)
s=0
for ((i = 1; i <= 100; i++)); do
s=$(($s + $i))
done
echo "The sum of 1 + 2 + ... + 99 + 100 is $s."
这种情况适用于知道循环次数。
eg. 批量创建用户。
#!/bin/bash
# 批量添加新用户。
# Author: geek(Email: YifanLiGeek@gmail.com)
# 输入用户名,等待时间 30s。
read -p "Please input user name: " -t 30 name
# 输入创建用户个数,等待时间 30s。
read -p "Please input the number of users: " -t 30 num
# 输入用户密码,等待时间 30s。
read -p "Please input the password of users: " -t 30 pass
# 判断输入信息是否为空。
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]; then
# 这里是判断输入的用户个数是否为数字,sed 后也可以把 '^[0-9]*$' 换为 's/[0-9]//g'。
y=$(echo $num | sed s/'^[0-9]*$'//g)
# 如果上一条语句输出不为空,就是输入的用户个数为数字,继续执行。
if [ -z "$y" ]; then
# 开始循环。
for ((i = 1; i <= $num; i++)); do
# 建立用户。
/usr/sbin/useradd "$name$i" &> /dev/null
# 设置用户密码,与用户名相同。
echo $pass | /usr/bin/passwd --stdin "$name$i" &> /dev/null
done
echo "build success!"
fi
fi
如果输入的时候输错了需要按,ctrl + 退格键。
while 循环与 until 循环。
while 循环。
while循环是不定循环,也称作条件循环 。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。这就和 for 的固定循环不太一样了。
while [ 条件判断式 ]; do
程序
done
eg. 从 1 加到 100。
#!/bin/bash
# 从 1 加到 100。
# Author: geek(Email: YifanLiGeek@gmail.com)
i=1
s=0
# 如果变量 i 的值小于等于 100,则执行循环。
while [ $i -le 100 ]; do
s=$(($s + $i))
i=$(($i + 1))
done
echo "The sum is: $s."
until 循环。
until 循环,和 while 循环相反,until 循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。
until [ 条件判断式 ]
do
程序
done
eg. 从 1 加到 100。
#!/bin/bash
# 从 1 加到 100。
# Author: geek(Email: YifanLiGeek@gmail.com)
i=1
s=0
# 循环直到变量 i 的值大于 100,就停止循环。
until [ $i -gt 100 ]; do
s=$(($s + $i))
i=$(($i + 1))
done
echo "The sum is: $s."