权限的基本介绍

我们使用ls -l(ll指令)指令的时候会发现有一串神秘的字符串,其实它就代表了文件的权限。它的每位都有特殊的含义。

文件权限

我们来看看这9位字符都告诉了我们什么,首先是第0位,它确定了文件的类型,-表示普通文件,i相当于链接,相当于Windows的快捷方式,d是目录,相当于Windows的文件夹,c是字符设备文件,像是鼠标、键盘之类的,b是块设备,比如硬盘。其次1-3位确定所有者拥有该文件的权限,r代表可读,w代表可写,对于目录来讲代表可修改,x表示可执行,对于目录来讲就是可进入。在着4-6位确定所属组拥有该文件的权限。最后7-9确定其他用户拥有该文件的权限。在日期前面还有一些数字,这些数字代表文件大小,至于所有者前面的数字代表硬链接数目,一个文件至少一个,一个文件夹至少两个。在Linux中r可以用4代替,w可以用2代替,x可以用1代替,所以全部的权限可以用7代替。

修改权限chmod指令

基本语法:

chmod u=rwx,g=rx,o=x 文件/目录名

chmod o+w 文件/目录名

chmod a-x 文件/目录名

其中u代表所有者,g代表所在组,o代表其他组,a代表所有,也就是u,g,o的总和。我们可以使用+,-,=变更权限。

chmod指令使用+,-,=

也可以用数字变更权限

chmod指令使用数字

shell编程

当我们将来走上工作,学会怎么写一个shell脚本是必不可少的,比如我们在进行服务器维护的时候,可能就会需要编写一个脚本来定时备份数据库等等。

shell是什么

知道shell可以做什么了,可是什么是shell呢?shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以通过shell来启动、挂起、停止甚至是编写一些程序。当然Linux不止一个shell,我们常用的是bash。

shell

shell脚本的执行方式

学习shell和我们学习其他语言是一样的我们先来看一下格式的要求,首先脚本要以 #!/bin/bash 开头,其次脚本要有可执行的权限。脚本常用的执行方式有两种,一是要先赋予我们写好的脚本文件x权限,然后输入脚本的绝对路径或相对路径执行,二是使用 sh 脚本这个指令来执行。

执行一个向屏幕输出hello world的程序

shell的变量

之前我们在汇编的学习中提到了,一个有用的程序,多半会存在变量,shell编程也是如此。Linux shell中的变量分为,系统变量和用户自定义变量,系统变量包括$HOME、$PWD、$SHELL、$USER等等,我们可以用set指令显示所有变量。

用户自定义变量的基本语法是:变量名=值,注意在Linux中指令对空格的检测很严格,所以一定要仔细看接下来的指令中是否含有空格,这点很重要!当我们需要删除一个变量的时候我们可以使用指令unset 变量名来进行销毁,我们还可以声明一个静态变量使用指令readonly变量,静态变量不可以被unset销毁掉。当我们输出一个变量的时候我们可以使用指令echo $A,注意$符号,当我们定义变量的时候不需要$但输出的时候需要(tips:#表示注释,多行注释为:<<!……!)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
#定义一个变量A
A=100
:<<!
输出变量需要$
echo指令可以使用“”也可以省略
!
echo A=$A
echo "A=$A"
#撤销变量A
unset A
echo A=$A
#声明静态变量B=2,不能被unset
readonly B=2
echo B=$B
exit 0

结果:

shell中的变量

在高级语言中,变量的定义是有规则的,在shell编程中也不例外,shell编程中,变量的名称可以由字母、数字和下划线组成,但不能以数字开头,变量定义时等号两边不能有空格,变量名称一般习惯为大写。

当我们希望将一个指令的返回值赋给一个变量,那我们需要使用反引号`(~键)或$()将指令包起来,否则shell认为是将指令本身赋给变量。例如:

1
2
3
4
5
6
7
8
#!/bin/bash
A=date
B=`date`
C=$(date)
echo $A
echo $B
echo $C
exit 0

结果:

将指令返回值赋给变量

shell字符串

字符串是 shell 编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。

单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。而双引号里可以出现变量,而且双引号里面可以含有转义字符。接下来是几个常用的字符串操作:

字符串拼接

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
your_name="liuzheng"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2 $greeting_3

结果:

字符串拼接

获取字符串长度

1
2
3
#!/bin/bash
your_name="liuzheng"
echo ${#your_name}

字符串拼接

提取字符串

1
2
3
#!/bin/bash
your_name="liuzheng"
echo ${your_name:0:3}

提取字符串

:0:3的意思是从第0位开始截取3个长度的字符。

查找子字符串

1
2
3
#!/bin/bash
your_name="liuzheng"
echo ${#your_name}

查找子字符串

设置环境变量

基本语法:export 变量名=变量值,用来将shell变量输出为环境变量(可以理解为全局变量,需要在/etc/profile中定义)

source 配置文件,用来让修改后的配置信息立即生效

echo $变量名,用来查询环境变量的值

1
2
3
4
5
#vim /etc/profile最下面,如果出现swap交换文件输入e即可
export myname=liuzheng
#命令行中
source /etc/profile
echo $myname

结果:

设置环境变量

位置参数变量

当我们执行一个shell脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量比如./myshell.sh 100 200,这就是一个执行shell的命令行,可以在myshell中获取到参数信息。

基本语法:

$n,n为数字,0代表命令本身,1-9代表第一个到第九个参数,十以上的参数需要用大括号包含如:${10}。

$*,这个变量表示命令行中所有的参数,它把所有参数看成一个整体。

$@,这个变量也代表命令行中所有参数,不过它把每个参数区分对待。

$#,这个变量表示命令行中所有参数个数,类似高级语言中main函数的变量argc。

1
2
3
4
5
6
7
8
#!/bin/bash
echo 0=$0
echo 1=$1
echo 2=$2
echo 所有参数=$*
echo $@
echo 参数个数$#
exit 0

结果:

位置参数变量

预定义变量

预定义变量是shell设计者已经实现定义好的变量,可以直接在shell脚本中使用,常用的有三个:

  1. $$,代表当前进程的进程号PID
  2. $!,代表后天运行的最后一个进程的进程号PID
  3. $?,代表最后一次执行的命令的返回状态,如果上一个命令正确执行那么返回的值为0,如果这个值非0着表示上一个命令执行不正确,至于错误后返回的到底是多少,由命令自己决定。
1
2
3
4
5
6
7
#!/bin/bash
echo 当前进程号为$$
#当我们需要在后台执行一个脚本的时候只需要在执行的指令后面加一个&即可
sh /home/liuzheng/shell/hello.sh &
echo 后台运行的最后一个进程号为$!
echo 最后一个命令是否成功执行$?
exit 0

结果:

预定义变量

运算符

我们在学习C语言的时候,肯定做过加法减法的程序,当然这也是计算机最基本的操作了,现在我们在shell中看看如何进行运算。

基本语法:

  1. $((运算式))或$[运算式]或者expr m +(-) n(注意格式)
  2. 注意运算符间要有空格
  3. 注意expr中乘法的写法为\*做转义操作
  4. 在使用expr进行运算时,如果要将计算结果赋值给一个变量,需要将运算式用反引号``括起来
1
2
3
4
5
6
#!/bin/bash
echo $[100+200]
A=`expr 100 \* 2`
echo $A
echo $(((2*4)+3))
exit 0

结果:

运算符

我们也可以通过之前学习的位置参数变量来优化脚本!

流程控制

我们在编写一个程序的时候,会对一些事情进行判断,如果满足了某一条件,我们就进行一系列操作,反之我们有别的应对,这个时候就要知道流程控制语句。

if语句和if……else语句

基本语法:if [ condition ]then …… fi,如果非空返回true。(注意格式,condition前后都有空格,if和中括号之间也有空格)

if [ condition ]then…… else…… fi,如果非空返回true。

我们在shell编程中常用的判断条件有四类:

1.字符串比较

  • =

2.两个整数比较

  • -lt 小于
  • -le 小于等于
  • -eq 等于
  • -gt 大于
  • -ge 大于等于
  • -ne 不等于

3.按照文件权限进行判断

  • -r 有读的权限
  • -w 有写的权限
  • -x 有执行的权限

4.按照文件类型进行判断

  • -f 文件存在且是一个常规的文件
  • -e 文件存在
  • -d 文件存在且是一个目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
if [ "ok"="ok" ]
then
echo isequal
fi
if [ 21 -ge 22 ]
then
echo yes
fi
echo exist?
if [ -f /home/liuzheng/shell/hello.sh ]
then
echo yes
fi
exit 0

结果:

if语句

if elif语句

我们已经学会了如何使用if,但有的时候判断会进行很多次,这个时候就要用到了else if,所以我们来看一下shell编程中else if是什么样子的。

基本语法(注意格式):

if [ condition ]then …… fi 或者 if [ condition ]then …… elif [ condition ] then …… fi

注意[ condition ],中括号和condition之间,if和中括号之间,elif和中括号之间必须有空格!!

1
2
3
4
5
6
7
8
9
#!/bin/bash
if [ $1 -ge 60 ]
then
echo 及格
elif [ $1 -lt 60 ]
then
echo 不及格
fi
exit 0

结果:

if elif语句

case语句

基本语法:

case $变量名 in 值1 )程序1;; 值2)程序2;; 值3)程序3;;…… * )如果变量的值都不是以上的值,执行本程序;; esac

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
case $1 in
1 )echo monday;;
2 )echo tuesday;;
3 )echo wednesday;;
4 )echo thursday;;
5 )echo friday;;
6 )echo saturday;;
7 )echo sunday;;
* )echo good day!;;
esac
exit 0

结果:

case语句

循环

现在我们需要像屏幕上输出1行hello world,你会选择使用echo hello world完成,如果我们需要输出10条,你可能会使用yy,p来完成,可是如果我们需要输出100条甚至更多呢?这个时候就要使用循环。

for循环

基本语法:

for 变量 in 值1 值2 值3 … do …… done,这里的值1,值2,值3代表一个集合 ,我们可以用省略号代表一个集合,比如1到100就是{1…100}

for (( 初始值;循环控制条件;变量变化 ))do……done

我们这里顺便使用for循环来看一下$*和$@的区别。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
echo *:
for i in "$*"
do
echo num is $i
done
echo =================
echo @:
for j in "$@"
do
echo num is $j
done
exit 0

结果:for循环1

1
2
3
4
5
6
7
8
#!/bin/bash
A=0
for (( i=1; i<=100; i++ ))
do
A=$[$A+$i]
done
echo $A
exit 0

结果:for循环2

while循环

基本语法:

while [ 条件判断式 ]do……done,注意while和[之间的空格,条件判断式前后的空格。

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
i=0
sum=0
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum
exit 0

结果:while循环

read读取控制台输入

基本语法:read (选项) (参数) 变量,用来读取键盘输入

选项:-p:指定读取值时的提示符

-t:指定读取值时等待的时间(秒),如果没有在指定的时间输入,就不在等待了

1
2
3
4
5
6
#!/bin/bash
read -p "请输入数字1" num1
echo "数字1为"$num1
read -t 10 -p "请在10s内输入数字2" num2
echo "数字2为"$num2
exit 0

结果:read读取控制台输入

函数

shell编程和其它的编程语言一样有函数的存在,函数可以被分为系统函数和自定义函数,接下来我们就来了解一下。

系统函数

1.基本语法:basename [pathname] [suffix]

basename [string] [suffix]

basename指令会删掉所有的前缀包括最后的一个/字符,然后将字符串显示出来。

选项:suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。

结果:basename指令

2.基本语法:dirname 文件绝对路径

dirname指令从给定的包含绝对路径的文件名中去除文件名,然后返回剩下来的路径。

结果:dirname指令

自定义函数

基本语法:

1
2
3
4
5
function funname()
{
Action;
[return int;]
}

当我们需要调用我们的自定义函数的时候,只需要写函数名即可。

1
2
3
4
5
6
7
8
9
#!/bin/bash
function getsum()
{
sum=$[$n1+$n2]
echo "和为"$sum
}
read -p "输入数字1:" n1
read -p "输入数字2:" n2
exit 0

结果:自定义函数

案例:who_is_up.sh

接下来我们一个案例体验一下shell编程带来的便利。

我们之前使用过ping指令,ping指令会通过发送数据包的形式判断目的主机是否宕机。接下来我们就用这个来看看都有谁在工作:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
for i in {1..254}
do
ping -c 2 -i 0.5 192.168.202.$i &> /dev/null
if [ $? -eq 0 ]
then
echo "192.168.202.$i is up"
else
echo "192.169.202.$i is down"
fi
done

结果:who_is_up.sh