您的当前位置:首页正文

shell脚本(基础、正则表达式、脚本)看这一篇就够了

来源:九壹网

shell

一。shell基础知识

1.什么是shell

Shell是系统跟计算机之间交互时使用的中间介质,他只是系统的一个工具。实际上,在shell和计算机硬件之间还有一层东西——系统内核。如果把计算机硬件比作一个人的躯体,那系统内核就是人的大脑。至此shell,把他比作人的五官似乎更贴切些。言归正传,用户直接面对的不是计算机硬件而是shell,用户把指令告诉shell,然后shell在传输给系统内核,接着内核再去支配计算机硬件去执行各种操作。

1.1记录命令历史

  ! 是与命令历史有关的一个特殊字符。该字符常用的应用有以下3个。

 !! :连续两个!!表示执行上一条指令。示例命令如下:

[root@localhost ~]#pwd

/root

[root@localhost ~]# !!

pwd

/root

!n :这里的n是数字,表示执行命令历史中的第n条指令。例如 !1002表示执行命令历史中的第1002个命令,如下所示:

[root@localhost ~]#history |grep 1002

  523  history |grep 1002

  525  history |grep 1002

[root@localhost ~]# !200

a=`date +%w`

上例中的history命令如果未改动过环境变量,默认可以把最近执行的1000条命令历史打印出来。

 

! 字符串(字符串大于等于1):例如 !pw表示执行命令历史中最近一次以pw开头的命令。示例代码如下:

[root@localhost ~]# !pw

pwd

/root

 1.2 命令和文件名补全

按tab键可以帮我们补全一个指令,一个路径或者一个文件名。连续按两次tab键,系统则会把所有的命令或者文件名都列出来

1.3 别名

alias,它也是bash所特有的功能之一。我们可以通过alias把一个常用的并且很长的指令另取名为一个简单易记的指令。如果不想用了,还可以使用unalias命令解除别名功能。直接执行aliens命令,会看到目前预设的别名,如下所示:

[root@localhost ~]# 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 which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

另外,也可以自定义命令的别名,其格式为alias [命令别名]=[‘具体的命令’], 示例命令如下:

[root@localhost ~]# alias aming='pwd'

[root@localhost ~]# aming

/root

[root@localhost ~]# unalias aming

[root@localhost ~]# aming

-bash: aming: 未找到命令

 

 

1.4 通配符

在bash下,可以使用*来匹配零个或多个字符,用?匹配一个字符。示例命令如下:

[root@localhost ~]# ls -d 123.*

123.x  123.y  123.z

[root@localhost ~]# touch 123.xxx

[root@localhost ~]# ls -d 123.?

123.x  123.y  123.z

 

1.5 输入/输出重定向

  输入输出重定向用于改变命令的输入,输出重定向用于改变命令输出。输出重定向更为常用,它经常用于将命令的结果输入文件中,而不是屏幕上。输入重定向的命令是<,输出重定向的命令是>,另外,还有错误重定向命令2>以及追加重定向命令>>,示例命令如下:

[root@localhost ~]# mkdir /tmp/10

[root@localhost ~]# cd /tmp/10

[root@localhost 10]# echo "123" > 1.txt

[root@localhost 10]# echo "123" >> 1.txt

[root@localhost 10]# cat 1.txt

123

123

1.6 管道符

它用于将前一个指令的输出作为后一个指令的输入,如下所示:

[root@localhost 10]# cat /etc/passwd|wc -l

19

2. 变量

比如环境变量PATH,它是shell预设的一个变量。通常,shell预设的变量都是大写的。变量就是使用一个较简单的字符串来代替某些具有特殊意义的设定以及数据。就拿PATH来说,这个PATH就代替了所有常用命令的绝对路径的设定。有了PATH这个变量,我们运行某个命令时,就不在需要输入全局路径,直接输入命令名即可。你可以使用echo命令显示变量的值,如下所示:

[root@localhost 10]# echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

[root@localhost 10]# echo $HOME

/root

[root@localhost 10]# echo $PWD

/tmp/10

[root@localhost 10]# echo $LOGNAME

root

2.1命令env

使用env命令,可列出系统预设的全部系统变量,如下所示:

[root@localhost ~]# env

XDG_SESSION_ID=19

HOSTNAME=localhost.localdomain

SELINUX_ROLE_REQUESTED=

TERM=vt100

SHELL=/bin/bash

HISTSIZE=1000

SSH_CLIENT=192.168.213.1 52011 22

SELINUX_USE_CURRENT_RANGE=

OLDPWD=/tmp/10

SSH_TTY=/dev/pts/0

USER=root

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:

MAIL=/var/spool/mail/root

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

PWD=/root

LANG=zh_CN.UTF-8

SELINUX_LEVEL_REQUESTED=

HISTCONTROL=ignoredups

SHLVL=1

HOME=/root

LOGNAME=root

SSH_CONNECTION=192.168.213.1 52011 192.168.213.101 22

LESSOPEN=||/usr/bin/lesspipe.sh %s

XDG_RUNTIME_DIR=/run/user/0

_=/usr/bin/env

登录不同的用户,这些环境变量的值也不同。当前显示的是root账户的环境变量。下面是常见的环境变量。

  env命令显示的变量只是环境变量,系统预设的变量其实还有很多,可以使用set命令把系统预设的全部变量都显示出来。

2.2 命令 set

Set命令喝env命令类似,也可以输出环境变量,如下所示:

[root@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=80

DIRSTACK=()

EUID=0

GROUPS=()

HISTCONTROL=ignoredups

HISTFILE=/root/.bash_history

HISTFILESIZE=1000

HISTSIZE=1000

HOME=/root

HOSTNAME=localhost.localdomain

HOSTTYPE=x86_64

IFS=$' \t\n'

LANG=zh_CN.UTF-8

LESSOPEN='||/usr/bin/lesspipe.sh %s'

LINES=23

LOGNAME=root

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/root

MAILCHECK=60

OLDPWD=/tmp/10

OPTERR=1

OPTIND=1

OSTYPE=linux-gnu

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

PIPESTATUS=([0]="127")

PPID=40069

PS1='[\u@\h \W]\$ '

PS2='> '

PS4='+ '

PWD=/root

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.213.1 52011 22'

SSH_CONNECTION='192.168.213.1 52011 192.168.213.101 22'

SSH_TTY=/dev/pts/0

TERM=vt100

UID=0

USER=root

XDG_RUNTIME_DIR=/run/user/0

XDG_SESSION_ID=19

_=aming

a=4

colors=/root/.dircolors

Set命令不仅可以显示系统预设的变量,也可以显示用户自定义的变量。比如我们自定义一个变量,如下所示:

[root@localhost ~]#  myname=Aming

[root@localhost ~]# echo $myname

Aming

[root@localhost ~]# set |grep myname

myname=Aming

虽然可以自定义变量,但是该变量只能在当前shell中生效,如下所示

[root@localhost ~]# echo $myname

Aming

[root@localhost ~]# bash    //执行该命令,会进入一个子shell环境中

[root@localhost ~]# echo $myname

[root@localhost ~]# exit

exit

[root@localhost ~]# echo $myname

Aming

使用bash命令可以在打开一个shell,此时先前设置的myname变量已经不存在了,退出当前shell回到原来的shell,myname变量还在。如果想让设置的环境变量一直生效,该怎么做呢? 这分为两种情况。

  1. 允许系统内所有用户登录后都能使用该变量。具体的操作方法是:在/etc/profile文件的最后一行加入export myname=Aming,然后运行source /etc/profile就可以生效了。此时再运行bash命令或者切换到其他账户(如su - test)就可以看到效果。如下所示:

[root@localhost ~]# echo "export myname=Aming" >> /etc/profile

[root@localhost ~]# source !$

source /etc/profile

[root@localhost ~]# bash

[root@localhost ~]# echo $myname

Aming

[root@localhost ~]# exit

Exit

[root@localhost ~]# useradd test

[root@localhost ~]# su - test

[test@localhost ~]$ echo $myname

Aming

上例中使用myname-Aming来设置变量myname,那么,在linux下自定义变量,有哪些规则

  1. 设定变量的格式为a=b,其中a为变量名,b为变量的内容,等号两边不能有空格。
  2. 变量名只能由字母、数字以及下划线组成,而且不能以数字开头。
  3. 当变量内容带有特殊字符(如空格)时,需要加上单引号,示例命令如下:

[root@localhost ~]# myname='Aming li'

[root@localhost ~]# echo $myname

Aming li

有一种情况需要你注意,就是变量内容中本身带有单引号,这时就需要加双引号了。示例命令如下:

[root@localhost ~]# myname="Aming'li"

[root@localhost ~]# echo $myname

Aming'li

如果变量内容中需要用到其他命令,运行结果则可以用反引号。示例命令如下

[root@localhost ~]# myname=`pwd`

[root@localhost ~]# echo $myname

/root

变量内容可以累加其他变量内容,但需要加双引号。示例命令如下

[root@localhost ~]# myname="$LOGNAME"Aming

[root@localhost ~]# echo $myname

rootAming

如果不下心把双引号错加为单引号,则得不到你想要的结果。示例命令如下

[root@localhost ~]# myname='$LOGNAME'Aming

[root@localhost ~]# echo $myname

$LOGNAMEAming

通过上面几个例子,能看出来使用单引号和双引号的区别。使用双引号时,不会取消双引号中特殊字符本身的作用(这里是$),而使用单引号时,里面的特殊字符将全部失去其本身的作用。

 

3.系统环境变量与个人环境变量的配置文件

  上面讲了很多系统变量,那么在linux系统中,这些变量存在哪里呢?为什么用户一登录shell就自动有了这些变量呢?先看下面几个文件。

  1. /etc/profile:这个文件预设了几个重要的变量,例如PATH、USER、LOGNAME、MAIL、INPUTRC、HOSTNAME、HISTSIZE、umask等。
  2. /etc/bashrc:这个文件主要预设umask以及PS1。这个PS1就是我们在输入命令时前面的那串字符。 例如,使用Linux系统的PS1就是[root@localhost]#,我们不妨看一下PS1的值,如下所示:

[root@localhost ~]# echo $PS1

[\u@\h \W]\$

  1. .bash_profile:该文件定义了用户的个人化路径与环境变量的文件名称。每个用户都可使用该文件输入专属于自己的shell信息,当用户登录时,该文件仅仅执行一次。
  2. .bashrc:该文件包含专属于自己的shell的bash信息,当登录或每次打开新的shell时,该文件会被读取。例如,你可以将用户自定义的别名或者自定义变量写到这个文件中。
  3. .bash_history:该文件用于记录命令历史
  4. .bash_logout:当退出shell时,会执行该文件。你可以将一些清理的工作放到这个文件中。

 

4.Linux shell中的特殊符号

4.1 *代表零个或者多个任意字符

前面提过此处

4.2 ?只代表一个任意字符

[root@localhost ~]# ls -d 123.*

123.x  123.y  123.z

[root@localhost ~]# touch 123.xxx

[root@localhost ~]# ls -d 123.?

123.x  123.y  123.z

4.3 注释符号#

这个符号在linux中表示注释说明,即后面的内容都会被忽略。用法如下:

[root@localhost ~]# abc=123 #aaaaa

[root@localhost ~]# echo $abc

123

 4.4脱义字符\

这个字符会将后面的特殊符号(如*)还原为普通字符。用法如下:

[root@localhost ~]# ls -d test\*

4.5 管道符|

这个字符前面曾多次出现过,它的作用是将前面命令的输出作为后面命令的输入。这里提到的后面的命令,并不是所有的命令都可以的,一般针对文档操作的命令比较常用。例如cat、less、head、tail、grep、cut、sort、wc、uniq、tee、tr、split、sed、awk等,其中grep、sed和awk是正则表达式必须掌握的工具。管道符的用法如下:

[root@localhost ~]# cat testb.txt |wc -l

0

在上例中,wc -l用来计算一个文档有多少行。

4.6 命令cut

cut命令用来截取某一个字段,其格式为cut -d 分割字符 [-cf] n,这里的n是数字。该命令有如下几个可用选项。

  1. -d:后面跟分割字符,分割字符要用单引号括起来。
  2. -c:后面接的是第几个字符。
  3. -f:后面接的是第几个区块。

cut命令的用法如下:

[root@localhost ~]# cat /etc/passwd|cut -d ':' -f 1 |head -5

root

bin

daemon

adm

lp

-d选项后面加冒号作为分隔字符,-f 1表示截取第一段,-f和1之间的空格可与可无。

示例命令如下:

[root@localhost ~]# head -n2 /etc/passwd|cut -c2

o

i

[root@localhost ~]# head -n2 /etc/passwd|cut -c1

r

b

[root@localhost ~]# head -n2 /etc/passwd|cut -c1-10

root:x:0:0

bin:x:1:1:

[root@localhost ~]# head -n2 /etc/passwd|cut -c5-10

:x:0:0

x:1:1:

-c选项后面可以是1个数字n,也可以是一个区间n1-n2,还可以是多个数字n1、n2和n3.

示例命令如下:

[root@localhost ~]# head -n2 /etc/passwd|cut -c1,3,10

ro0

bn:

4.7命令sort

sort命令用作排序,其格式为sort [ -t 分隔符 ] [-kn,n2] [-nru]、这里的n1和n2表示的是数字,其他选项的含义如下。

  1. -t:后面跟分割字符,作用跟cut的-d选项一样。
  2. -n:表示使用纯数字排序。
  3. -r:表示反向排序。
  4. -u:表示去重复。
  5. -kn1,n2:表示由n1区间排序到n2区间,可以只写-kn1,即对n1字段排序。

如果sort不加任何选项,则从首字母符向后依次按ASCII码值进行比较,最后将他们按升序输出。示例命令如下:

[root@localhost ~]# head -n5 /etc/passwd|sort

adm:x:3:4:adm:/var/adm:/sbin/nologin

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

root:x:0:0:root:/root:/bin/bash

-t选项后面跟分隔符,-k选项后面跟单个数字表示对第几个区域的字符串排序,-n选项表示使用纯数字排序。示例命令如下:

[root@localhost ~]# head -n5 /etc/passwd|sort -t: -k3 -n

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

-k选项后面跟数字n1和n2表示对第n1和n2区域内的字符串排序, -r选项则表示反向排序。示例命令如下:

[root@localhost ~]# head -n5 /etc/passwd|sort -t: -k3 -r

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

bin:x:1:1:bin:/bin:/sbin/nologin

root:x:0:0:root:/root:/bin/bash

这里的-k3,5表示对第3区域至第五区域间的字符串排序。

4.8 命令wc

wc命令统计文档的行数、字符数或词数。该命令的常用选项-l(统计行数)、-m(统计字符数)和-w(统计词数)。示例命令如下:

[root@localhost ~]# wc /etc/passwd

 20  28 885 /etc/passwd

[root@localhost ~]# wc -l /etc/passwd

20 /etc/passwd

[root@localhost ~]# wc -m /etc/passwd

885 /etc/passwd

[root@localhost ~]# wc -w /etc/passwd

28 /etc/passwd

如果wc不跟任何选项,直接跟文档,则会把行数、词数和字符数依次输出。

4.9命令uniq

uniq命令用来删除重复的行,该命令只有-c选项比较常用,它表示统计重复的行数,并把行数写在前面。我们先来编写一个文件,示例命令如下:

[root@localhost ~]# cat testb.txt

111

222

111

333

使用uniq前,必须先给文件排序,否则不管用。示例命令如下:

[root@localhost ~]# uniq testb.txt

111

222

111

333

[root@localhost ~]# sort testb.txt |uniq

111

222

333

[root@localhost ~]# sort testb.txt |uniq -c

      2 111

      1 222

      1 333

4.10 命令tee

  Tee命令后跟文件名,其作用类似于重定向>,但它比重定向多一个功能,即把文件写入后谜案所跟的文件时,还显示在屏幕上。该命令用于管道符|后。示例命令如下:

[root@localhost ~]# echo "aaaaaaaaaaaaaaa" |tee testb.txt

aaaaaaaaaaaaaaa

[root@localhost ~]# cat testb.txt

aaaaaaaaaaaaaaa

4.11 命令tr

tr命令用于替换字符,常用来处理文档中出现的特殊符号,如DOS文档中出现的符^M。该命令常用的选项有以下两个。

  1. -d:表示删除某个字符,后面跟要删除的字符。
  2. -s:表示删除重复的字符。

tr命令常用于把小写字母变成大写字母,如tr ‘[a-z]’ ‘ [A-Z]’。示例命令如下:

[root@localhost ~]# head -n2 /etc/passwd |tr '[a-z]' '[A-Z]'

ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH

BIN:X:1:1:BIN:/BIN:/SBIN/NOLOGIN

tr命令还可以替换一个字符,示例命令如下:

[root@localhost ~]# grep 'root' /etc/passwd |tr 'r' 'g'

goot:x:0:0:goot:/goot:/bin/bash

opegatog:x:11:0:opegatog:/goot:/sbin/nologin

不过替换、删除以及去重复等操作都是针对一个字符来讲的,有一定的局限性。如果是针对一个字符串,就不能再使用了,所以先只需要简单了解一下tr命令即可

4.12 命令split

split命令用于切割文档,常用的选项为-b和-l。

  1. -b:表示依据大小来切割文档,单位为byte,示例命令如下:

[root@localhost ~]# mkdir split_dir

[root@localhost ~]# cd !$

cd split_dir

[root@localhost split_dir]# cp /etc/passwd ./

[root@localhost split_dir]# split -b 500 passwd

[root@localhost split_dir]# ls

passwd  xaa  xab

如果split不指定目标文件名,则会以xaa、下、xbb...这样的文件名来存取切割后的文件。当然,我们也可以指定目标文件名,如下所示:

[root@localhost split_dir]# rm -f xa*

[root@localhost split_dir]# split -b 500 passwd 123

[root@localhost split_dir]# ls

123aa  123ab  passwd

-l:表示依据行数来切割文档,示例命令如下:

[root@localhost split_dir]# rm -f 123a*

[root@localhost split_dir]# split -l 10 passwd

[root@localhost split_dir]# wc -l *

  20 passwd

  10 xaa

  10 xab

  40 总用量

4.13特殊符号$

符号$可以用作变量前面的标识符,还可以和!结合起来使用。示例命令如下:

[root@localhost split_dir]# cd ..

[root@localhost ~]# ls testb.txt

testb.txt

[root@localhost ~]# ls !$

ls testb.txt

testb.txt

!$表示上条命令中的最后一个变量,本例中上条命令最后是testb.txt,那么在当前命令下输入!$则代表testb.txt。

4.14特殊符号;

通常,我们都是在一行中输入一个命令,然后回车就运行了。如果想在一行中运行两个或两个以上的命令,需要在命令之间加符号;。示例命令如下:

[root@localhost ~]# mkdir testdir ; touch test1.txt ; touch test2.txt; ls -d test*

test1.txt  test2.txt  testb.txt  testdir

4.15 特殊符号~

示例命令如下:

[root@localhost ~]# cd ~

[root@localhost ~]# pwd

/root

[root@localhost ~]# su aming

[aming@localhost root]$ cd ~

[aming@localhost ~]$ pwd

/home/aming

[aming@localhost ~]$

4.16 特殊符号&

如果想把一条命令放在后台之执行,则需要加上符号&,它通常用于命令运行时间较长的情况。比如,可以用在sleep后,如下所示:

[root@localhost ~]# sleep 30 &

[1] 40772

[root@localhost ~]# jobs

[1]+  运行中               sleep 30 &

4.17 重定向符号>、>>、2>和2>>

前面讲过重定向符号>和>>,它们分别表示取代和追加的意思。当我们运行一个命令报错时,报错信息会输出到当前屏幕。如果想重定向到一个文本,则要用重定向符号2>>或者2>>,它们分别表示错误重定向和错误追加重定向。示例命令如下:

[root@localhost ~]# ls aaaa

[root@localhost ~]# ls aaaa 2> /tmp/error

[root@localhost ~]# cat /tmp/error

[root@localhost ~]# ls aaaa 2>> /tmp/error

[root@localhost ~]# cat /tmp/error

4.18 中括号[]

中括号内为字符组合,代表字符组合中的任意一个,可以是一个范围(1-3,a-z),用法如下:

[root@localhost 10]# cd

[root@localhost ~]# cd /tmp/10

[root@localhost 10]# ls -d test*

test1.txt  test2.txt  test3.txt  testdir

[root@localhost 10]# ls -d test[1-3].txt

test1.txt  test2.txt  test3.txt

[root@localhost 10]# ls -d test[12b].txt

test1.txt  test2.txt

[root@localhost 10]# ls -d test[1-9].txt

test1.txt  test2.txt  test3.txt

[root@localhost 10]# ls -d test[1-9a-z].txt

test1.txt  test2.txt  test3.txt

4.19特殊符号&&和||

前面提到了分号可作为多条命令间的分隔符,其实还有两个可以用与多条命令中间的特殊符号,那就是&&和||。

列出以下几种情况:

  1. command1 ; command2
  2. command1 && command2
  3. command1 || command2   

使用;时,不管command1是否执行成功,都会执行command2.

使用&&时,只有command1执行成功后,command2才会执行,否则command2不执行

使用||时,command执行成功后则command2才会执行,否则执行command2,即command1和command2中总有一条命令会执行。接下来,做个测试

[root@localhost 10]# rm -rf test*

[root@localhost 10]# touch test1 test3

[root@localhost 10]# ls test2 && touch test2

[root@localhost 10]# ls test2

本例中,只有当ls test2执行成功后,才会执行touch test2.因为test2不存在,ls test2没有执行成功,所以&&后面的touch并没有执行。

[root@localhost 10]# ls test2 || touch test2

[root@localhost 10]# ls test*

test1  test2  test3

本例中,若ls test2执行不成功,则会执行touch test2。因为test2不存在,所以ls test2没有执行成功,转而执行||后面的touch test2,所以增加了test2这个文件。

二。正则表达式

在计算机科学中,对“正则表达式”的定义是:它使用单个字符串来描述或匹配一系列符合某个句法规则的字符串。在很多文本编辑器或其他工具里,正则表达式通常用来检索和替换那些符合某个模式的文本内容。许多程序设计语言也都支持利用正则表达式进行字符串操作。对于系统管理员来讲,正则表达式贯穿在我们的日常运维工作中,无论是查找某个文档,还是查询某个日志文件并分析其内容,都会用到正则表达式。

其实正则表达式只是一种思想、一种表示方法。只要我们使用的工具支持这种表示方法,那么这个工具就可以处理正则表达式的字符串。常用的工具有grep、sed、awk等,其中grep、sed和awk都是针对文本的行进行操作的,下面分别介绍一下这3种工具的使用方法。

1.grep/egrep工具的使用

该命令的格式为:grep [-cinvABC] ‘word’ filename,其常用的选项如下所示。

  1. -c:表示打印符合要求的行数
  2. -i:表示忽略大小写
  3. -n:表示输出符合要求的行及其行号
  4. -v:表示打印不符合要求的行
  5. -A:后面跟一个数字(有无空格都可以),例如-A2表示打印符合要求的行以及下面两行。
  6. -B:后面跟一个数字,例如-B2表示打印符合要求的行以及上面两行。
  7. -C:后面跟一个数字,例如-C2表示打印符合要求的行以及上下各两行。

先来测试 -A 、-B和 -C这三个选项的用法。

-A2会把包含halt的行以及这行下面的两行都打印出来:

[root@localhost ~]# grep -A2 'halt' /etc/passwd

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

-B2会把包含halt的行以及这行上面的两行都打印出来:

[root@localhost ~]# grep -B2 'halt' /etc/passwd

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

-C 会把包含halt的行以及这行上下各两行都打印出来。

[root@localhost ~]# grep -C2 'halt' /etc/passwd

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

1.1过滤出带有某个关键字的行,并输入行号

示例命令如下:

[root@localhost ~]# grep -n 'root' /etc/passwd

1:root:x:0:0:root:/root:/bin/bash

10:operator:x:11:0:operator:/root:/sbin/nologin

1.2 过滤出不带有某个关键词的行,并输入行号

示例命令如下:

[root@localhost ~]# grep -nv 'nologin' /etc/passwd

1:root:x:0:0:root:/root:/bin/bash

6:sync:x:5:0:sync:/sbin:/bin/sync

7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

8:halt:x:7:0:halt:/sbin:/sbin/halt

20:test:x:1000:1000::/home/test:/bin/bash

21:aming:x:1001:1001::/home/aming:/bin/bash

1.3过滤出所有包含数字的行

示例命令如下:

[root@localhost ~]# grep '[0-9]' /etc/inittab

# multi-user.target: analogous to runlevel 3

# graphical.target: analogous to runlevel 5

1.4过滤出所有不包含数字的行

示例命令如下:

[root@localhost ~]# grep -v '[0-9]' /etc/inittab

# inittab is no longer used when using systemd.

#

# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.

#

# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target

#

# systemd uses 'targets' instead of runlevels. By default, there are two main targets:

#

#

# To view current default target, run:

# systemctl get-default

#

# To set a default target, run:

# systemctl set-default TARGET.target

#

1.5 过滤掉所有以#开头的行

示例命令如下:

[root@localhost ~]# cat /etc/sos.conf

[plugins]

#disable -rpm. selinux, dovecot

[tunables]

#rpm.rpmva - off

#general.syslogsize - 15

#grep -v '^#' /etc/sos.conf

[plugins]

[tunables]

1.6 过滤掉所有空行和以#开头的行

[root@localhost ~]# grep -v '^#' /etc/sos.conf |grep -v '^$'

[plugins]

[tunables]

[plugins]

[tunables]

在正则表达式中,^表示行的开始,$表示行的结尾,那么空行则可以用^$表示。如何打印出不以英文字母开头的行呢?我们先来自定义一个文件,如下所示

[root@localhost ~]# mkdir /tmp/1

[root@localhost ~]# cd /tmp/1

[root@localhost 1]# vi test.txt

[root@localhost 1]# cat test.txt

123

abc

456

abc2323

#laksdjf

Alllllll

先写几行字符串,用来做实验 如下所示

[root@localhost 1]# grep '^[^a-zA-Z]' test.txt

123

456

#laksdjf

[root@localhost 1]# grep '[^a-zA-Z]' test.txt

123

456

abc2323

#laksdjf

前面提到过中括号[]的应用,如果时数字就用[0-9]这样的形式(当遇到类似[15]的形式时,表示只含有 1或者5).如果要过滤数字以及大小写字母,则要写成类似[0-9a-zA-Z]的形式。另外,[^字符]表示除了[]内字符之外的字符。请注意,把^写到方括号里面和外面是有区别的。

1.7过滤出任意一个字符和重复字符

示例命令如下:

[root@localhost 1]# grep 'r.o' /etc/passwd

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

.表示任意一个字符。上例中,r.o表示把r与o之间有一个任意字符的行过滤出来。

[root@localhost 1]# grep 'ooo*' /etc/passwd

root:x:0:0:root:/root:/bin/bash

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

*表示零个或多个*前面的字符。上例中,ooo*表示oo,ooo,oooo或者更多的o。

[root@localhost 1]# grep '.*' /etc/passwd |wc -l

21

[root@localhost 1]# wc -l /etc/passwd

21 /etc/passwd

上例中,.*表示零个或多个任意字符,空行也包含在内,它会把/etc/passwd文件里面的所有行都匹配到,也可以不加|wc -l 看一下效果

[root@localhost 1]# grep '.*' /etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin

dbus:x:81:81:System message bus:/:/sbin/nologin

polkitd:x:999:998:User for polkitd:/:/sbin/nologin

sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

chrony:x:998:996::/var/lib/chrony:/sbin/nologin

test:x:1000:1000::/home/test:/bin/bash

aming:x:1001:1001::/home/aming:/bin/bash

1.8 指定要滤出的字符出现次数

示例命令如下:

[root@localhost 1]# grep 'o\{2\}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

这里用到了符号{},其内部为数字,表示前面的字符要重复的次数。需要强调的是, {}左右都需要加上转义字符\。另外,使用 “{ }”还可以表示一个范围,具体格式为{n1,n2},其中n1<n2,表示重复n1到n2次前面的字符,n2还可以为空,这时表示大于等于n1次。

除grep工具外,也常常用到egrep这个工具,后者是前者的扩展版本,可以完成grep不能完成的工作。下面说几个egreep不同于grep的几个用法。为了后续试验方便把test.txt编辑成如下文件

[root@localhost 1]# cat test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

1.9 过滤出一个或多个指定的字符

示例命令如下:

[root@localhost 1]# egrep 'o+' test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

[root@localhost 1]# egrep 'oo+' test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

[root@localhost 1]# egrep 'ooo+' test.txt

roooot:x:0:0:/rooooot:/bin/bash

和egrep不同,这里egrep使用的是符号+,它表示匹配1个或多个+前面的字符,这个 “+”

是不是支持被grep直接使用的。包括上面的{}。也是可以直接被egrep使用,而不用家\转义。示例如下:

[root@localhost 1]# egrep 'o{2}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

1.10 过滤出零个或一个指定的字符

示例命令如下:

[root@localhost 1]# egrep 'o?' test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

[root@localhost 1]# egrep 'ooo?' test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

[root@localhost 1]# egrep 'oooo?' test.txt

roooot:x:0:0:/rooooot:/bin/bash

1.11过滤出字符串1或者字符串2

示例命令如下:

[root@localhost 1]# egrep 'aaa|111|ooo' test.txt

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

1.12  egrep中()的应用

示例命令如下

[root@localhost 1]# egrep 'r(oo|at)o' test.txt

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

这里的()表示一个整体,上例中会把包含rooo或者rato的行过滤出来,另外也可以把()和其他符号组合在一起,例如(oo)+就表示1个或者多个oo。如下所示

[root@localhost 1]# egrep '(oo)+' test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

2.sed工具的使用

其实grep工具的功能还不够强大,它实现的只是查找功能,二不能把查找的内容替换。以前用vi操作文档的时候,可以查找也可以替换,但是限于在文本内部操作,二不能输出到屏幕上。sed工具以及后面要介绍的awk工具就能把替换的文本输出到屏幕上,而且还有其他更丰富的功能。sed和awk都是流式编辑器,是针对文档紧凑型来操作的

2.1 打印某行

Sed命令的格式为: sed -n ‘n’p filename, 单引号内的n是一个数字,表示第几行。-n选项的作用是只显示我们要打印的行,无关紧要的内容不显示。

示例命令如下

[root@localhost 1]# sed -n '2'p /etc/passwd

bin:x:1:1:bin:/bin:/sbin/nologin

可以去掉-n选项对比一下差异。要想把所有行都打印出来,可以使用命令sed -n ‘1,$’ p filename 如下所示:

[root@localhost 1]# sed -n '1,$'p test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

当然也可以指定一个区间打印,如下所示:

[root@localhost 1]# sed -n '1,3'p test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

2.2打印包含某个字符串的行

示例命令如下

[root@localhost 1]# sed -n '/root/'p test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

这种用法就类似于grep了,在grep中使用的特殊字符(如^、 $、.、*等)同样也能在sed中使用,如下所示:

[root@localhost 1]# sed -n '/^1/'p test.txt

1111111111111111111111111111111

[root@localhost 1]# sed -n '/in$/'p test.txt

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

[root@localhost 1]# sed -n '/r..o/'p test.txt

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

[root@localhost 1]# sed -n '/ooo*/'p test.txt

rot:x:0:0:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

sed命令加上-e选项可以实现多个行为,如下所示:

[root@localhost 1]# sed -e '1'p -e '/111/'p -n test.txt

rot:x:0:0:/root:/bin/bash

1111111111111111111111111111111

2.3删除某些行

示例命令如下:

[root@localhost 1]# sed '1'd test.txt

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

[root@localhost 1]# sed '1,3'd test.txt

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

[root@localhost 1]# sed '/oot/'d test.txt

1111111111111111111111111111111

这里参数d表示删除的动作,它不仅可以删除指定的单行以及多行,而且可以删除指定的单行及多行,而且可以删除匹配某个字符的行,还可以删除从某一行开始到文档最后一行的所有行。不过,这个操作仅仅实在显示屏幕上并不是显示这些行而已,文档还好好的

2.4替换字符或者字符串

示例命令让如下:

[root@localhost 1]# sed '1,2s/ot/to/g' test.txt

rto:x:0:0:/roto:/bin/bash

operator:x:11:0:operator:/roto:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

上例参数s就表示替换的动作,参数g表示本行全局替换,如果不加g则只替换本行出现的第一个,这个用法其实和vi的替换大同小异。

除了可以使用/作为分隔符外,我们还可以使用其他特殊字符,例如#和@。如下所示:

[root@localhost 1]# sed 's#ot#to#g' test.txt

rto:x:0:0:/roto:/bin/bash

operator:x:11:0:operator:/roto:/sbin/nologin

operator:x:11:0:operator:/rototo:/sbin/nologin

roooto:x:0:0:/rooooto:/bin/bash

1111111111111111111111111111111

[root@localhost 1]# sed 's@ot@to@g' test.txt

rto:x:0:0:/roto:/bin/bash

operator:x:11:0:operator:/roto:/sbin/nologin

operator:x:11:0:operator:/rototo:/sbin/nologin

roooto:x:0:0:/rooooto:/bin/bash

1111111111111111111111111111111

现在思考一下:如何删除文档中所有的数字或字母? 示例命令如下:

[root@localhost 1]# sed 's/[0-9]//g' test.txt

rot:x:::/root:/bin/bash

operator:x:::operator:/root:/sbin/nologin

operator:x:::operator:/rootot:/sbin/nologin

roooot:x:::/rooooot:/bin/bash

[0-9]表示任意的数字。这里你也可以写成[a-zA-ZA]或者[0-9a-zA-Z].如下所示:

[root@localhost 1]# sed 's/[a-zA-Z]//g' test.txt

::0:0:/://

::11:0::/://

::11:0::/://

::0:0:/://

1111111111111111111111111111111

2.5 调换两个字符串的位置

[root@localhost 1]# sed 's/\(rot\)\(.*\)\(bash\)/\3\2\1/' test.txt

bash:x:0:0:/root:/bin/rot

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

小括号在sed中属于特殊符号,必须在前面家转义字符\,替换时则携程类似\1、\2、或\3的形式。上例中用()把想要替换的字符打包成了一个整体。有这个转义字符\,会让这个表达式看起来乱糟糟的有个办法可以省略它。如下所示;

[root@localhost 1]# sed -r 's/(rot)(.*)(bash)/\3\2\1/' test.txt

bash:x:0:0:/root:/bin/rot

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rootot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

没错,正如你看到的,就是这个-r选项让这个表达式更加清晰了。除了调换两个字符串的位置,还常常用sed在某一行前后增加指定内容,如下所示:

[root@localhost 1]# sed 's/^.*$/123&/' test.txt

123rot:x:0:0:/root:/bin/bash

123operator:x:11:0:operator:/root:/sbin/nologin

123operator:x:11:0:operator:/rootot:/sbin/nologin

123roooot:x:0:0:/rooooot:/bin/bash

1231111111111111111111111111111111

2.6 直接修改文件的内容

示例命令如下:

[root@localhost 1]# sed -i 's/ot/to/g' test.txt

[root@localhost 1]# cat test.txt

rto:x:0:0:/roto:/bin/bash

operator:x:11:0:operator:/roto:/sbin/nologin

operator:x:11:0:operator:/rototo:/sbin/nologin

roooto:x:0:0:/rooooto:/bin/bash

1111111111111111111111111111111

这样就可以直接更改test.txt文件中的内容了。但必须注意,在修改前最好先备份一下文件,以免改错。

 

3.awk工具的使用

awk也是流式编辑器,针对文档中的行来操作,一行一行地执行。awk兼具sed的所有功能,而且更加强大。

3.1 截取文档中的某个段

示例命令如下:

[root@localhost 1]# head -n2 test.txt |awk -F ':' '{print $1}'

rto

operator

本例中,-F选项的作用是指定分隔符。如果不加-F选项,则以空格或者tab为分隔符。Print为打印动作,用来打印某个字段。$1为第一个字段。$2为第2个字段,以此类推。但$0比较特殊,它表示整行:

[root@localhost 1]# head -n2 test.txt |awk -F':' '{print $0}'

rto:x:0:0:/roto:/bin/bash

operator:x:11:0:operator:/roto:/sbin/nologin

注意awk的格式,-F后面紧跟单引号,单引号里面为分隔符。Print的动作要用{}括起来,否则会报错。print还可以打印自定义的内容,但是自定义的内容要用双引号括起来。如下所示:

[root@localhost 1]# head -n2 test.txt |awk -F':' '{print $1"#"$2"#"$3"#"$4}'

rto#x#0#0

operator#x#11#0

3.2 匹配字符或者字符串

示例命令如下:

[root@localhost 1]# awk '/oo/' test.txt

roooto:x:0:0:/rooooto:/bin/bash

3.3条件操作符

示例命令如下:

[root@localhost 1]# awk -F ':' '$3=="0"' /etc/passwd

root:x:0:0:root:/root:/bin/bash

awk中可以用逻辑符号进行判断,比如==就是等于,也可以理解为精确匹配。另外还有>、>=、<、<=、!=等。值得注意的是,在和数字比较时,若把比较的数字用双引号引起来,那么awk不会认为是数字,而会认为是字符,不加双引号则会认为是数字。

[root@localhost 1]# awk -F ':' '$3>"500"' /etc/passwd

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

dbus:x:81:81:System message bus:/:/sbin/nologin

polkitd:x:999:998:User for polkitd:/:/sbin/nologin

sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

chrony:x:998:996::/var/lib/chrony:/sbin/nologin

本例中,本想把uid大于等于500的行打印出来,但是结果并不理想。这是因为awk把所有的数字当作字符了,就跟上一章中提到的sort排序原理一样。但,不加双引号就得到了想要的结果:

[root@localhost 1]# awk -F ':' '$3>500' /etc/passwd

polkitd:x:999:998:User for polkitd:/:/sbin/nologin

chrony:x:998:996::/var/lib/chrony:/sbin/nologin

test:x:1000:1000::/home/test:/bin/bash

aming:x:1001:1001::/home/aming:/bin/bash

本例中,!=表示不匹配,它除了针对某一个字段的字符进行逻辑比较外,还可以在两个段之间进行逻辑比较。如下所示:

[root@localhost 1]# awk -F ':' '$3<$4' /etc/passwd

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

另外还可以使用&&和||,他们分别表示“并且”和“或者”。&&的用法如下:

[root@localhost 1]# awk -F ':' '$3>"5" && $3<"7"' /etc/passwd

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

||的用法如下:

[root@localhost 1]# awk -F ':' '$3>1000 || $7=="/bin/bash"' /etc/passwd

root:x:0:0:root:/root:/bin/bash

test:x:1000:1000::/home/test:/bin/bash

aming:x:1001:1001::/home/aming:/bin/bash

3.4 awk的内置变量

awk常用的变量有OFS、NF和NR,OFS和-F选项有类似的功能,也是用来定义分割符的,但是它是在输出的时候定义,NF表示用分隔符分隔后一共有多少段,NR表示行号。

OFS的用法示例如下:

[root@localhost 1]# head -5 /etc/passwd |awk -F ':' '{OFS="#"} {print $1,$3,$4}'

root#0#0

bin#1#1

daemon#2#2

adm#3#4

lp#4#7

还有更高级的用法:

[root@localhost 1]# awk -F ':' '{OFS="#"} {if ($3>1000) {print $1,$2,$3,$4}}' /etc/passwd

aming#x#1001#1001

变量NF的具体用法如下:

[root@localhost 1]# head -n3 /etc/passwd | awk -F ':' '{print NF}'

7

7

7

[root@localhost 1]# head -n3 /etc/passwd | awk -F ':' '{print $NF}'

/bin/bash

/sbin/nologin

/sbin/nologin

这里NF是多少段,$NF是最后一段的值。变量NR的具体用法如下:

[root@localhost 1]# head -n3 /etc/passwd | awk -F ':' '{print NR}'

1

2

3

我们还可以使用NR作为判断条件,如下所示:

[root@localhost 1]# awk 'NR>15' /etc/passwd

polkitd:x:999:998:User for polkitd:/:/sbin/nologin

sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

chrony:x:998:996::/var/lib/chrony:/sbin/nologin

test:x:1000:1000::/home/test:/bin/bash

aming:x:1001:1001::/home/aming:/bin/bash

NR也可以配合段匹配一起使用,如下所示:

[root@localhost 1]# awk -F ':' 'NR<20 && $1 ~ /root/' /etc/passwd

root:x:0:0:root:/root:/bin/bash

3.5 awk中的数学运算

awk可以更改段值,示例命令如下:

[root@localhost 1]# head -n 3 /etc/passwd |awk -F ':' '$1="root"'

root x 0 0 root /root /bin/bash

root x 1 1 bin /bin /sbin/nologin

root x 2 2 daemon /sbin /sbin/nologin

awk也可以对各个段的值进行数学运算,示例命令如下:

[root@localhost 1]# head -n2 /etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

[root@localhost 1]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4}'

[root@localhost 1]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4; print $0}'

root x 0 0 root /root 0

bin x 1 1 bin /bin 2

awk还可以计算某个段的总和,示例命令如下:

[root@localhost 1]# awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd

4606

这里的END是awk特有的语法,表示所有的行都已经执行。其实awk连同sed都可以写成一个脚本文件,而且有它们特有的语法。在awk中使用if判断、for循环都可以,只是日常生活中没有必要使用那么复杂的语句。如下所示:

[root@localhost 1]# awk -F ':' '{if ($1=="root") {print $0}}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

 

三.shell脚本

前言

Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。然而Shell本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,但是 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。

Shell 也是一种脚本语言,是系统命令的集合,可以使用逻辑判断、循环等语法,可以自定义函数,我们编写完源码后不用编译,直接运行源码即可。

Shell脚本是在Linux的shell中运行的,所以称为shell脚本。本质上,shell脚本就是一些命令的集合。shell脚本可以实现自动化运维,所以能帮助我们很方便的管理服务器;比如我们可以指定一个任务计划,定时的去执行某个shell脚本已满足需求。

1.shell脚本结构与执行

1.1脚本结构

第一行一定是:#/bin/bash  该命令说明,该文件使用的是,bash语法,如果不设置改行,则该脚本不会被执行。 以#开头的作为解释说明。Shell脚本通常以sh为后缀,用于区分这是一个Shell脚本。

下面来编写一个shell脚本,如下所示:

[root@localhost ~]# mkdir shell

[root@localhost ~]# cd shell

[root@localhost shell]# vi 1.sh     //写入如下内容

#!/bin/bash

touch /tmp/1.txt

chmod 600 /tmp/2.txt

mv /tmp/1.txt /tmp/2.txt

 

1.2 脚本执行

接下来执行1.1编写的脚本,如下所示:

[root@localhost shell]# bash 1.sh

其实shell脚本还有一种执行方法,但前提是脚本本身要有执行权限,所以在执行前我们需要给脚本加一个x权限。如下所示:

[root@localhost shell]# ./1.sh
-bash: ./1.sh: Permission denied
[root@localhost shell]# chmod +x 1.sh    //赋予权限
[root@localhost shell]# ./1.sh        //执行脚本

2.常用命令

2.1查看脚本执行过程

[root@localhost shell]# bash -x 1.sh

+ touch /tmp/1.txt

+ chmod 600 /tmp/2.txt

+ mv /tmp/1.txt /tmp/2.txt

2.2查看脚本是否有语法错误

[root@localhost shell]# bash -n 1.sh

2.3 data 命令

2.3.1 显示年、月、日
date +%Y-%m-%d    #年(以四位数字格式打印年份)月日

date +%y-%m-%d    #年(以两位数字格式打印年份)月日

date +%F         #年(以四位数字格式打印年份)月日

2.3.2显示小时、分钟、秒
date +%H:%M:%S    #小时分钟秒

date +%T           #小时分钟秒

2.3.3显示星期
date +%w          #一周中的第几天

date +%W          #一年中的第几周

2.3.4时间戳

使用命令date +%s 显示从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数。示例如下:

使用命令 date -d @164082388 显示输入秒数之前的时间。示例如下:

2.3.5 显示一个小时之前/之后
date -d "+1 hour"    #一个小时后

date -d "-1 hour"    #一个小时前

2.3.6 表示一天之前/之后
date -d "+1day"     #一天后

date -d "-1 day"     #一天前

3.shell脚本中的变量

在shell脚本中使用变量可以节省时间并且使我们的脚本更加专业,所以当我们编写一个脚本时,就可以使用变量来代替某个使用频繁并且长度很长的字符串。变量的格式:“变量名=变量的值”。

3.1引用命令的结果

当我们引用某个命令的结果时,可以使用变量替代,示例如下:

[root@localhost ~]# a=`date +%w`         #将命令结果赋值给变量

[root@localhost ~]# echo $a

6

[root@localhost ~]# a=$(date +%w)        #将命令结果赋值给变量

[root@localhost ~]# echo $a

6

由上例可知,如果我们需要将命令结果赋值给变量,可以采用示例中两种形式的其一来实现。

3.2与用户交互

示例如下:

[root@localhost ~]# read -p "请输入一个数字:" n

请输入一个数字:10

[root@localhost ~]# echo $n

10

[root@localhost ~]# read -p "请输入一个数字:"

请输入一个数字:100

[root@localhost ~]# echo $REPLY

100

3.3内置变量

示例如下:

[root@localhost shell]# vi bian.sh         #创建一个名为bian.sh的脚本

[root@localhost shell]# cat bian.sh

#!/bin/bash

echo "\$1=$1"

echo "第二个参数是$2"

echo "第三个参数是$3"

echo "本脚本一共有$#个参数"

echo "\$0是$0"



[root@localhost shell]# sh bian.sh         #执行脚本

$1=

第二个参数是

第三个参数是

本脚本一共有0个参数

$0是bian.sh



[root@localhost shell]# sh bian.sh a b         #再次执行脚本

$1=a

第二个参数是b

第三个参数是

本脚本一共有2个参数

$0是bian.sh                       # $0就是脚本的名字

在 Bash 脚本中,内置变量用于存储和传递脚本运行时的信息。这些变量通常以 $ 符号开头。以下是一些常见的内置变量及其用途:

1.$0:

  1. 代表当前脚本的名称。如果脚本是通过相对路径或绝对路径调用的,则 $0 包含该路径。
  2. 示例:bian.sh

   

2.$1 到 $9:

  1. 分别代表传递给脚本的第1到第9个参数。
  2. 示例:如果执行 sh bian.sh a b,那么 $1 是 a$2 是 b

3.$#:

  1. 表示传递给脚本的参数个数。
  2. 示例:如果执行 sh bian.sh a b,那么 $# 是 2

4.$@:

  1. 所有传递给脚本的参数列表。与 $* 不同的是,"$@" 会将每个参数分别处理,而不是作为一个整体。
  2. 示例:如果执行 sh bian.sh a b c,那么 "$@" 展开为 a b c

5.$*:

  1. 类似于 $@,但是稍有不同。"$*" 会将所有参数当作一个整体,用第一个参数的分隔符(默认是空格)连接起来。
  2. 示例:如果执行 sh bian.sh a b c,那么 "$*" 展开为 a b c

  6.$$:

  1. 当前脚本的进程 ID (PID)。
  2. 示例:假设脚本运行时的 PID 是 1234,那么 $$ 就是 1234

7.$?

  1. 上一个命令的退出状态。成功返回 0,非零表示失败。
  2. 示例:如果上一个命令成功执行,$? 就是 0

8.$_:

  1. 最后一个后台运行的命令的退出状态(仅限 Bash)。
  2. 示例:类似于 $?,但仅适用于后台进程。

理解这些内置变量,你可以编写更加动态和强大的脚本,能够更好地处理用户输入和脚本运行环境。

3.4数学运算

shell脚本中的变量常用于数学运算当中,示例如下:

[root@localhost shell]# vi sum.sh      #创建一个名为sum.sh的脚本

[root@localhost shell]# cat sum.sh

#!/bin/bash

a=1

b=2

sum=$[$a+$b]          #还可以采用sum=$(($a+$b))这种写法

echo "$a+$b=$sum"

[root@localhost shell]# sh sum.sh       #执行脚本

1+2=3

4.Shell中的逻辑判断

在shell脚本中,逻辑判断语句通常用于根据条件执行不同的命令。带有else的逻辑判断语句会在条件成立时执行if后面的命令,否则执行else后面的命令。而不带有else的逻辑判断语句只会在条件成立时执行if后面的命令,否则什么都不做。

原理上,逻辑判断语句通过比较两个值的大小、相等性或其他关系来判断条件是否成立。常见的比较操作符有:

  1. -eq:等于
  2. -ne:不等于
  3. -gt:大于
  4. -ge:大于等于
  5. -lt:小于
  6. -le:小于等于

4.1不带有else

基础结构:

if  判断语句; then

    command

fi

示例如下:

[root@localhost shell]# vi if1.sh

[root@localhost shell]# cat if1.sh

#!/bin/bash



a=10

if [ $a -gt 4 ]

then

echo ok

fi



[root@localhost shell]# sh -x if1.sh     #执行脚本

+ a=10

+ '[' 10 -gt 4 ']'

+ echo ok

ok

[root@localhost shell]# sh -n if1.sh

在这个示例中,我们创建了一个名为if1.sh的shell脚本。脚本首先定义了一个变量a,并将其值设置为10。接下来,我们使用if语句来判断变量a的值是否大于4。如果条件成立(即a大于4),则执行echo ok命令。最后,我们使用fi来结束if语句。

当我们执行这个脚本时,首先会显示+ a=10,表示变量a被赋值为10。接下来,+ '[' 10 -gt 4 ']'表示判断a是否大于4,结果为真。然后,+ echo ok表示执行echo ok命令,输出"ok"。所以最后的输出结果是"ok"

4.2带有else

基础结构:

if  判断语句  ; then

    command

else

    command

fi

示例如下:

[

root@localhost shell]# vi if2.sh

[root@localhost shell]# cat if2.sh

#!/bin/bash



a=10

if [ $a -gt 4 ]

then

echo ok

else

echo "not ok"

fi



[root@localhost shell]# sh -x if2.sh        #执行脚本

+ a=10

+ '[' 10 -gt 4 ']'

+ echo ok

ok

在这个示例中,我们创建了一个名为if2.sh的shell脚本。脚本首先定义了一个变量a,并将其值设置为10。接下来,我们使用if语句来判断变量a的值是否大于4。如果条件成立(即a大于4),则执行echo ok命令。否则,执行echo "not ok"命令。最后,我们使用fi来结束if语句。

当我们执行这个脚本时,首先会显示+ a=10,表示变量a被赋值为10。接下来,+ '[' 10 -gt 4 ']'表示判断a是否大于4,结果为真。然后,+ echo ok表示执行echo ok命令,输出"ok"。所以最后的输出结果是"ok"。

4.3带有elif

示例如下:

[root@localhost shell]# vi if3.sh

[root@localhost shell]# cat if3.sh

#!/bin/bash



a=3

if [ $a -gt 4 ]

then

echo ok

elif [ $a -gt 8 ]

then

echo "very ok"

else

echo "not ok"

fi



[root@localhost shell]# sh -x if3.sh     #执行脚本

+ a=3

+ '[' 3 -gt 4 ']'

+ '[' 3 -gt 8 ']'

+ echo 'not ok'

not ok

在这个示例中,我们创建了一个名为if3.sh的shell脚本。脚本首先定义了一个变量a,并将其值设置为3。接下来,我们使用if语句来判断变量a的值是否大于4。如果条件成立(即a大于4),则执行echo ok命令。否则,我们使用elif语句来判断a是否大于8。如果条件成立(即a大于8),则执行echo "very ok"命令。最后,如果前面的所有条件都不成立,则执行else后面的命令,输出"not ok"。最后,我们使用fi来结束if语句。

当我们执行这个脚本时,首先会显示+ a=3,表示变量a被赋值为3。接下来,+ '[' 3 -gt 4 ']'表示判断a是否大于4,结果为假。然后,+ '[' 3 -gt 8 ']'表示判断a是否大于8,结果也为假。因此,程序将执行else后面的命令,输出"not ok"。所以最后的输出结果是"not ok"。

4.4嵌套

示例如下:

[root@localhost shell]# vi if4.sh

[root@localhost shell]# cat if4.sh

#!/bin/bash



a=10

if [ $a -gt 4 ]

then

if [ $a -lt 20 ]

then

echo "ok"

else

echo "very ok"

fi

else

echo "not ok"

fi



[root@localhost shell]# sh -x if4.sh       #执行脚本

+ a=10

+ '[' 10 -gt 4 ']'

+ '[' 10 -lt 20 ']'

+ echo ok

ok

在这个示例中,我们创建了一个名为if4.sh的shell脚本。脚本首先定义了一个变量a,并将其值设置为10。接下来,我们使用if语句来判断变量a的值是否大于4。如果条件成立(即a大于4),则进入内部的if语句。

在内部的if语句中,我们再次判断a的值是否小于20。如果条件成立(即a小于20),则执行echo "ok"命令。否则,执行echo "very ok"命令。

最后,如果外部的if语句的条件不成立(即a不大于4),则执行else后面的命令,输出"not ok"。最后,我们使用fi来结束if语句。

当我们执行这个脚本时,首先会显示+ a=10,表示变量a被赋值为10。接下来,+ '[' 10 -gt 4 ']'表示判断a是否大于4,结果为真。然后,+ '[' 10 -lt 20 ']'表示判断a是否小于20,结果也为真。因此,程序将执行内部if语句中的echo "ok"命令,输出"ok"。所以最后的输出结果是"ok"。

4.5 多个条件

if [ $a -gt 5 ] && [ $a -lt 10 ] == if [ $a -gt 5 -a $a -lt 10]     # -a表示 and

if [ $b -gt 5 ] || [ $b -lt 3] == if [ $b -gt 5 -o $b -lt 3 ]        # -o表示 or

4.6 If逻辑判断

4.6.1 if判断文件的目录属性
  1. -e:判断文件或目录是否存在。
  2. -d:判断是不是目录以及是否存在。
  3. -f:判断是不是普通文件以及是否存在。
  4. -T:判断是否有读权限。
  5. -w:判断是否有写权限。
  6. -X:判断是否可执行。

注意:root用户对文件的读写比较特殊,即使一个文件没有给root用户读或者写的权限,root也可以读或者写。

4.6.2 if判断的一些特殊用法

命令 if [ -z "$a" ]; 表示当变量a的值为空时会怎么样,如下图所示:

命令  if [ -n "$a" ]; 表示当变量a的值不为空时会怎么样,如下图所示:

说明一下

在这个命令中,! 是一个逻辑运算符,表示“非”或“不是”。它通常与 -z 一起使用,用于检查一个字符串是否为空。

具体来说,[ ! -z "$a$" ] 这个条件判断语句的意思是:如果变量 $a 不为空(即长度大于0),则执行后面的代码块。反之,如果 $a 为空(即长度为0),则不执行后面的代码块。

加这个 ! 和不加的区别如下:

[ -z "$a$" ]:这个命令会检查变量 $a 是否为空。如果为空,那么条件成立,执行后面的代码块;如果不为空,那么条件不成立,不执行后面的代码块。

[ ! -z "$a$" ]:这个命令使用了逻辑非运算符 !,它会反转前面的条件。所以,这个命令实际上是检查变量 $a 是否不为空。如果不为空,那么条件成立,执行后面的代码块;如果为空,那么条件不成立,不执行后面的代码块。

总结一下,[ ! -z "$a$" ] 和 [ -z "$a$" ] 的作用是相反的。前者检查变量 $a 是否不为空,后者检查变量 $a 是否为空。

命令 if grep -q '123' 1.sh; then 表示如果1.sh中含有123会怎么样,其中-q表示即使过滤出内容也不要打印出来,如下图所示:

 if (($a<1)); then 等同于 if [ $a -lt 1 ];then 二者都可以用来进行判断,需要注意的是,当我们未对变量a进行赋值时则会报错,如下图所示:

注意:[ ]中不能使用<,>,==,!=,>=,<=这样的符号,需要时要使用固定写法 -gt (>); -lt(<); -ge(>=); -le(<=);-eq(==); -ne(!=)。

4.7shell中的case判断

case判断的基础格式如下:

case 变量 in

value1)                    #不限制value的个数

command

;;

value2)

command

;;

*)                         #此处*代表其他值

command

;;

esac

为了让我们能够更加清晰的理解case逻辑判断,接下来我们编写一个脚本来进行实验,内容如下:

[root@localhost shell]# vi case.sh

#!/bin/bash

read -p "Please input a number:" n  #提示用户输入一个数字并将其存储在变量n中

if [ -z "$n" ]                    #检查变量n是否为空

then

   echo "Please input a number."  #如果n为空,则输出提示信息

   exit 1                     #退出脚本并返回错误码1

fi



n1=`echo $n|sed 's/[0-9]//g'`   #使用sed命令将n中的非数字字符替换为空,然后将结果存储在变量n1中。

if [ -n "$n1" ]               #检查变量n1是否不为空

then

 echo "Please input a number."  #如果n1不为空,说明n中包含非数字字符,输出提示信息

 exit 1                      #退出脚本并返回错误码1

fi



if [ $n -lt 60 ] && [ $n -ge 0 ]   #判断输入的数字是否在0到60之间(包括0和60)

then

    tag=1

elif [ $n -ge 60 ] && [ $n -lt 80 ] #判断输入的数字是否在60到80之间(包括60和80)

then

    tag=2

elif [ $n -ge 80 ] && [ $n -lt 90 ] #判断输入的数字是否在80到90之间(包括80和90)

then

    tag=3

elif [ $n -ge 90 ] && [ $n -le 100 ]  #判断输入的数字是否在90到100之间(包括90和100)

then

    tag=4

else         # 如果输入的数字不在上述范围内,则设置tag为0

    tag=0

fi

case $tag in        #根据tag的值执行相应的命令

   1)

     echo "not ok"    #如果tag为1,输出"not ok"

     ;;

   2)

     echo "ok"      #如果tag为2,输出"ok"

     ;;

   3)

     echo "very ok"   #如果tag为3,输出"very ok"

     ;;

   4)

     echo "oook"     #如果tag为4,输出"oook"

     ;;

   *)

     echo "The number range is 0-100."   #如果tag为其他值,输出"The number range is 0-100."

     ;;

esac       # 结束case语句

执行结果:

 

5.shell中的循环

5.1for 循环

基础结构如下:

for 变量名 in 循环条件;

do

command

done

这是一个Bash脚本,用于计算1到10的和。脚本中使用了for循环,循环变量为i,循环条件为seq 1 10,表示从1到10的整数序列。在循环体内,每次将i的值累加到sum变量中,并输出当前的i值。最后输出累加后的sum值

下面进行一个简单的实验演示,演示如下:

[root@localhost shell]# vi for1.sh

#!/bin/bash   #是脚本的shebang,指定脚本使用的解释器为bash

sum=0        #初始化一个名为sum的变量,初始值为0

for i in `seq 1 10`   #定义一个for循环,循环变量为i,循环条件为seq 1 10,即从1到10的整数序列

do             #循环体的开始

   sum=$[$sum+$i]    #将sum的值加上当前循环变量i的值,并将结果赋值给sum

   echo $i         #输出当前循环变量i的值

done            #循环体的结束

echo $sum       #输出累加后的sum值

执行结果:

5.2 while循环

基础结构:

while 条件; do

command

done

示例1:

[root@localhost shell]# vi while1.sh

#!/bin/bash

while :               #此处冒号表示死循环

do

load=`w|head -1|awk -F 'load average:' '{print $2}'|cut -d. -f1`     #赋值给变量load

if [ $load -gt 10 ]       #判断负载平均值是否大于10

then              #如果满足条件,执行以下操作

top|mail-s "load is high: $load" asldkfls011.com  #发送一封邮件通知管理员。这里使用了top命令获取系统进程信息,并通过mail命令发送邮件。邮件的主题是"load is high: $load",收件人地址为asldkfls011.com。

fi

sleep 30  #等待30秒后再次执行循环

done

运行结果:

示例2:

[

root@localhost shell]# vi while2.sh          #创建一个脚本

#!/bin/bash

while :

do

  read -p "Please input a number: " n  #提示用户输入一个数字,并将输入的值存储在变量n中

  if [ -z "$n" ]            #检查变量n是否为空,如果为空,则执行下面的代码块

  then

      echo "you need input sth."   #输出提示信息,告诉用户需要输入内容

      continue              #跳过当前循环的剩余部分,直接进入下一次循环

  fi

  n1=`echo $n|sed 's/[0-9]//g '`  #使用sed命令将变量n中的非数字字符替换为空,然后将结果存储在变量n1`中

  if [ -n "$n1" ]      #检查变量n1是否不为空,如果不为空,说明用户输入了非数字字符,执行下面的代码块

  then

      echo "you just only input numbers."  #出提示信息,告诉用户只能输入数字

      continue       #跳过当前循环的剩余部分,直接进入下一次循环

  fi

  break

done

echo $n

运行结果:

 

6.Shell中的中断与继续

6.1 跳出循环

break在脚本中表示跳出该层循环,示例如下:

[root@localhost shell]# vi break1.sh

#!/bin/bash

for i in `seq 1 5`

do

   echo $i

   if [ $i -eq 3 ]

   then

       break

   fi

  echo $i

done

echo aaaaa

执行结果:

在Shell脚本中,break命令用于跳出当前循环。当执行到break时,程序会立即退出当前的循环结构(如for、while等),并继续执行循环之后的代码。

的示例中,break1.sh脚本使用了一个for循环来遍历数字1到5。在每次循环中,首先输出当前的数字,然后判断这个数字是否等于3。如果等于3,就执行break命令,跳出循环。否则,继续执行循环。

由于break命令的存在,当i等于3时,循环会被中断,因此只会输出1、2和3。之后,脚本会继续执行循环之后的代码,即输出"aaaaa"。

6.2结束本次循环

当在shell脚本中使用continue时,结束的不是整个循环,而是本次循环。忽略continue之下的代码,直接进行下一次循环。示例如下:

[root@localhost shell]#vi continue1.sh         #创建一个shell脚本

#!/bin/bash

for i in `seq 1 5 `

do

   echo $i

   if [ $i == 3 ]

   then

       continue          #此处continue表示若 $i == 3 则结束本次循环

   fi

   echo $i

done

echo $i

执行结果:

在Shell脚本中,continue命令用于结束当前循环的剩余部分,并立即开始下一次循环。当执行到continue时,程序会跳过当前循环体中continue之后的所有代码,直接进入下一次循环。

示例中,continue1.sh脚本使用了一个for循环来遍历数字1到5。在每次循环中,首先输出当前的数字,然后判断这个数字是否等于3。如果等于3,就执行continue命令,跳过本次循环的剩余部分(即不执行echo $i),直接进入下一次循环。否则,继续执行循环。

由于continue命令的存在,当i等于3时,不会输出3,而是直接进入下一次循环。因此,最终只会输出1、2、4和5。之后,脚本会继续执行循环之后的代码,即输出最后一个变量i的值(此时i为5)。

6.3 退出整个脚本

当我们在shell脚本中遇到exit时,其表示直接退出整个shell脚本。示例如下:

[root@localhost shell]# vi exit1.sh

#!/bin/bash

for i in `seq 1 5`

do

   echo $i

   if [ $i == 3 ]

   then

       exit

   fi

   echo $i

done

echo aaaa

执行结果:

在Shell脚本中,exit命令用于立即退出整个脚本。当执行到exit时,程序会立即终止当前脚本的执行,并返回一个退出状态码(默认为0,表示成功)。

示例中,exit1.sh脚本使用了一个for循环来遍历数字1到5。在每次循环中,首先输出当前的数字,然后判断这个数字是否等于3。如果等于3,就执行exit命令,直接退出整个脚本。否则,继续执行循环。

由于exit命令的存在,当i等于3时,循环会被中断,并且整个脚本也会立即退出。因此,只会输出1和2,而不会输出3、4、5以及"aaaa"。

7.Shell中的函数

shell脚本中的函数就是先把一段代码整理到了一个小单元中,并给这个小单元命名,当我们用到这段代码时直接调用这个小单元的名字就可以了,这样很方便,省时省力。但我们需要注意,在shell脚本中,函数一定要写在前面,因为函数要被调用的,如果还未出现就被调用就会出错。

基础格式:

function f_name()

{

command

}

函数定义

Input() {

    echo $1 $2 $3 $0

}

  1. Input 是函数的名称。
  2. $1 和 $2 分别表示第一个和第二个参数。
  3. $# 表示传递给函数的参数个数。
  4. $0 表示脚本的名字。

函数调用

Input 1 a b

调用 input 函数,并传递三个参数 1,a和b

7.1打印出第一个、第二个参数、参数的个数及脚本名

示例如下:

[root@localhost shell]# vi fun1.sh

#/bin/bash

input()

{

echo $1 $2 $# $0         # 函数的参数:$1 $2 $# ;$0则是脚本的名字

}

input 1 a b

执行结果:

7.2 加法的函数

示例如下:

[root@localhost shell]# vi fun2.sh

#!/bin/bash

sum()

{

s=$[$1+$2]

echo $s

}

sum 1 2

执行结果:

7.3获得一个网卡的IP地址

示例如下:

[root@localhost shell]# vi fun3.sh

#!/bin/bash

ip()

{

ifconfig |grep -A1 "$1: " |tail -1 |awk '{print $2}'

}

read -p "Please input the eth name: " e

myip=`ip $e`

echo "$e address is $myip"

执行结果:

 8.shell中的数组

8.1数组读取

首先我们需要先定义一个数组a=(1 2 3 4 5);

命令 echo ${a[@]} 读取数组中的全部元素。示例如下:

命令 echo ${#a[@]} 获取数组的元素个数。示例如下:

命令 echo ${a[2]} 读取第三个元素,数组从0开始。示例如下:

echo ${a[*]} 等同于 ${a[@]}  作用为显示整个数组。示例如下:

8.2 数组赋值

a[1]=100; echo ${a[@]}  替换指定的元素值。示例如下:

a[5]=2; echo ${a[@]}  如果下标不存在则会自动添加一个元素。示例如下:

a[7]=6; echo ${a[@]}   跳着添加元素时,中间未赋值的元素,不显示且无值。示例如下:

8.3 数组的删除

命令unset a[1] 用于删除单个元素。示例如下:

命令unset a 用于删除整个数组。示例如下:

8.4 数组分片

在进行实验操作之前,需要对一个数组进行赋值  a=(`seq 1 5`) 。

命令echo ${a[@]:0:3}  表示从第一个元素开始,截取3个元素,并打印出来。示例如下:

命令echo ${a[@]:1:4}  表示从第二个元素开始,截取4个元素,并打印出来。示例如下:

echo ${a[@]:0-3:2}  表示从倒数第3个元素开始,截取2个元素,并打印出来。示例如下:

8.5 数组替换

使用命令echo ${a[@]/b/100}   表示用100替换b,但不会保存替换,只是打印出来。示例如下:

使用命令a=(${a[@]/b/100})   表示用100替换b,这种方法不仅可以打印出来还可以保存替换。示例如下:

如果感觉对您有帮助动动你发财的小手一键三连呦!

后续还会持续更新以及脚本案例

因篇幅问题不能全部显示,请点此查看更多更全内容

Top