Shell

就是一个命令行的解释器,接收用户命令,调用系统内核

查看所有支持的 shell

cat /etc/shells

Ubuntu默认的shell解释器是 dash ,centos默认的shell解释器是 bash
查看当前shell解释器:

echo $SEHLL

格式

第一行以:

#!/bin/bash

开头,代表指定解释器为bash

hello world

#!/bin/bash
echo "hello world"

执行方式

无需执行权限

source 文件.sh
sh 文件.sh
bash 文件.sh

需要权限

./文件.sh

区别: shbash 都会开启一个子shell,而 source 将会直接在当前shell中执行,有时候更改了系统环境变量不会立即生效,而需要使用source继续更新一下

在子shell中设置的环境变量父shell是不可见

如果想要在一行中执行多个命令,可以用 ; 进行隔开:

➜  shell echo "aaaa" echo "bbbb"
aaaa echo bbbb
➜  shell echo "aaaa";echo "bbbb"
aaaa
bbbb

变量

定义的局部、全局变量 set

分为全局变量和局部变量

  • 全局变量:父子shell都可见的变量
  • 局部变量:只对当前shell有效的变量
  • 默认情况下所有的变量都是字符串类型

系统与定义的环境变量都是以 $ 开头的

查看所有全局环境变量 env

变量名=值,等号前后不能够有空格,如果值中有空格,需要加引号,单双引号都可以

unset 取消变量

➜  shell a=222
➜  shell echo $a           
222
➜  shell unset a
➜  shell a="hello world"
➜  shell echo $a
hello world

可以将其设置为一个全局变量,全局变量在子shell中也可以访问到,但其他shell中访问不到,需要先有局部变量才能定义全局变量,以下方式可以定义全局变量j

export 局部变量名

子shell修改了全局变量后,不影响父shell,在父shell中更改了会影响子shell,就近原则


有以下脚本 hello.sh

➜  shell cat hello.sh      
#!/bin/bash
echo $a
echo $a
echo $a
echo $b

执行方式:

➜  shell a="hello world....."
➜  shell export a    
➜  shell b="hello shell"      
➜  shell source hello.sh
hello world.....
hello world.....
hello world.....
hello shell
➜  shell ./hello.sh
hello world.....
hello world.....
hello world.....

➜  shell bash hello.sh  
hello world.....
hello world.....
hello world.....

➜  shell sh hello.sh
hello world.....
hello world.....
hello world.....

数学运算:

➜  shell echo $((1+5))
6
➜  shell echo $[1+5]  
6

常量(只读变量)

定义方式,只读变量也不能撤销

readonly 变量=值

如果再尝试赋值,将会报错:

➜  shell b=565656       
zsh: read-only variable: b
➜  shell unset b
zsh: read-only variable: b

特殊变量

$n(功能描述:n 为数字,$0 代表该脚本名称,$1-9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如9 代表第一到第九个参数,十以 上的参数,十以上的参数需要用大括号包含,如{10})

使用echo输出内容时,单引号中会将 $内容 当成字符串处理,而双引号会将 $内容 当成变量处理

$#获取所有的参数个数

功能描述:这个变量代表命令行中所有的参数,*功能描述:这个变量代表命令行中所有的参数,*把所有的参数看成一个整体)
@(功能描述:这个变量也代表命令行中所有的参数,不过@ (功能描述:这个变量也代表命令行中所有的参数,不过@把每个参数区分对待)

#!/bin/bash
echo "你好,文件名为:${0},参数个数为${#}"
echo "参数1为:${1}"
echo "参数2为:${2}"
echo "所有的参数信息为:${*}"
echo "所有的参数信息数组为:${@}"
echo "返回值:$?"

运算

需要使用 expr

例如

expr 1 + 2

运算符两侧需要有空格,加减除正常运算即可,乘号需要转义: expr 2 \* 3

echo "$1 + $2 = $(($1+$2))"

#!/bin/bash
a=$(($1*$2))
echo "$1 + $2 = $a"

条件

0代表true,1代表false

基本语法
(1)test condition
(2)[ condition ](注意 condition 前后要有空格)
注意:条件非空即为 true
2)常用判断条件
(1)两个整数之间比较
-eq 等于(equal)-ne 不等于(not equal)
-lt 小于(less than)-le 小于等于(less equal)
-gt 大于(greater than)-ge 大于等于(greater equal)
注:如果是字符串之间的比较 ,用等号“=”判断相等;用“!=”判断不等。
(2)按照文件权限进行判断
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
(3)按照文件类型进行判断
-e 文件存在(existence)
-f 文件存在并且是一个常规的文件(file)
-d 文件存在并且是一个目录(directory)

➜  shell test 0 = 0 
➜  shell echo $?   
0
➜  shell test 0 = 1
➜  shell echo $?
1

➜  shell [ 0 = 0 ]
➜  shell echo $?
0
➜  shell [ 0 = 1 ]
➜  shell echo $?
1

➜  shell [ $a -eq 1000000 ]
➜  shell echo $?
0
➜  shell [ $a -eq 0 ] 
➜  shell echo $?

➜  shell [ $a -eq 0 ] 
➜  shell echo $?
1
➜  shell [ a != 10 ] 
➜  shell echo $?
0
➜  shell [ 2 -le 2 ]
➜  shell echo $?
0
➜  shell [ 2 -ge 2 ]
➜  shell echo $?
0
➜  shell [ 2 -lt 5 ]
➜  shell echo $?
0
➜  shell [ 2 -gt 1 ]
➜  shell echo $?
0

判断权限

➜  shell touch b.sh                   
➜  shell ll
总计 4.0K
-rw-rw-r-- 1 songxiaoxu songxiaoxu  0  5月  6 22:20 b.sh
-rwxr--r-- 1 songxiaoxu songxiaoxu 44  5月  6 21:58 hello.sh
➜  shell [ -r b.sh ]
➜  shell echo $?
0
➜  shell [ -x b.sh ]
➜  shell echo $?
1
➜  shell [ -w b.sh ]
➜  shell echo $?

判断类型

➜  shell [ -e b.sh ]
➜  shell echo $?
0
➜  shell [ -e c.sh ]
➜  shell echo $?
1
➜  shell [ -f b.sh ]
➜  shell echo $?
0
➜  shell mkdir abc    
➜  shell ls
abc  b.sh  hello.sh
➜  shell [ -f abc ] 
➜  shell echo $?
1
➜  shell [ -d abc ]
➜  shell echo $?
0
➜  shell [ -d b.sh ]
➜  shell echo $?
1

多条件

&& 前一条成功,后一条才执行

|| 前一条失败,后一条才执行

➜  shell [ 1 = 1 ] && [ 2 = 2 ]     
➜  shell echo $?                    
0
➜  shell [ 1 = 1 ] && [ 2 = 3 ]
➜  shell echo $?               
1
➜  shell [ 1 = 1 ] || [ 2 = 3 ]
➜  shell echo $?
0
➜  shell [ 2 = 5 ] || [ 6 = 7 ]
➜  shell echo $?
1
➜  shell [ 2 = 2 ] && echo 第一个条件成立
第一个条件成立
➜  shell [ 2 = 22 ] && echo 第一个条件成立
➜  shell [ 2 = 2 ] && echo 第一个条件成立 && [ 3 = 3 ] && echo 第二
个条件成立
第一个条件成立
第二个条件成立
➜  shell [ 2 = 2 ] && echo 第一个条件成立 || [ 3 = 3 ] && echo 第二个条件成立
第一个条件成立
第二个条件成立
➜  shell [ 2 = 2 ] && echo 第一个条件成立 || [ 3 -ne 3 ] && echo 第二个条件成立
第一个条件成立
第二个条件成立
➜  shell [ 2 = 3 ] || echo 第一条失败
第一条失败
➜  shell [ 2 != 3 ] || echo 第一条失败
➜  shell [ 2 != 3 ] || echo 第一条失败
➜  shell echo $?
0
➜  shell echo $?                    
0
➜  shell a=100    
➜  shell [ $a = 100 ] && echo $a=100 || echo $a!=100
100=100
➜  shell [ $a = 200 ] && echo $a=100 || echo $a!=200
100!=200

流程控制

单分支

if [ 条件判断式 ];then
程序
fi

或者

if [ 条件判断式 ]
then
程序
fi

多分支

if [ 条件判断式 ]
then
程序
elif [ 条件判断式 ]
then
程序
else
程序
fi

①[ 条件判断式 ],中括号和条件判断式之间必须有空格
②if 后要有空格

可能出现传入的值为空的情况,如果值为空将会报错,这时候需要:

if [ "$1"x = "5"x ]
then
    echo "$1 == 5"
else
    echo "$1 != 5"
fi

多个条件可以合并到一块:

  • -a and
  • -o or
if [ $1 = 5 ] || [ $1 = 10 ]
then
    echo "$1 为5或者10"
else
    echo "$1 不为5或者10"
fi

可以表示为

if [ $1 = 5 -o $1 = 10 ]
then
    echo "$1 为5或者10"
else
    echo "$1 不为5或者10"
fi
if [ $1 -gt 5 -a $1 -lt 10 ]
then
    echo "$1 大于5或者小于10"
else
    echo "$1"
fi

switch

语法

case 变量名 in 
case $变量名 in
"值 1")
如果变量的值等于值 1,则执行程序 1
;;
"值 2")
如果变量的值等于值 2,则执行程序 2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac

(1)case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
(2)双分号“;;”表示命令序列结束,相当于 java 中的 break。
(3)最后的“*)”表示默认模式,相当于 java 中的 default。

for循环

格式

for ((初值;条件;表达式))
do
	语句
done

求和

sum=0;
for ((i=0;i<101;i++))
do
    sum=$((sum+i))
done

echo $sum

sum=0
for ((i = 0; i < 101; i++)); do
    sum=$((sum + i))
done

echo $sum

for in格式

for 变量 in 值1 值2 值3; do
	语句
done

for 变量 in 值1 值2 值3
do
	语句
done

例如打印所有的参数

#!/bin/bash
for i in "$@"; do
    echo "参数:$i"
done
for i in aa bb cc dd ee
do
    echo $i
done

可以通过 {开始..结束} 来生成字符序列

➜  shell echo {1..100}          
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

求和

#!/bin/bash
sum=0
for i in {1..100}; do
    sum=$(($sum+$i))
done
echo $sum

while循环

格式

while [ 条件 ]; do
  语句
done

while [ 条件 ]
do
	语句
done

求和

#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]; do
    sum=$(($sum + $i))
    i=$(($i + 1))
done

echo $sum

可以用let实现其他编程语言的写法,运算符左右依旧不能有空格

#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]; do
    let sum+=i
    let i++
done

echo $sum

读取控制台

格式

read 选项 参数

例如:

#!/bin/bash
read -p "输入内容:" content
echo "你输入的内容为:$content"

例如5秒内读取内容

read -t 5 -p "输入内容:" content
echo "你输入的内容为:$content"

函数

linux系统中也提供了一些函数

例如 basename 函数,可以获取一个路径中的文件名,例如:

➜  shell basename /home/songxiaoxu/program/shell.txt
shell.txt
➜  shell basename /home/songxiaoxu/program/shell.txt .txt
shell

dirname 函数,可以获取路径

➜  shell dirname /home/songxiaoxu/program/shell.txt
/home/songxiaoxu/program

格式:

# 完整格式
[ function ] funname[()]
{
	Action;
	[return int;]
}
# 省略格式
函数名() {

}
  • 调用之前先声明
  • 返回值可以通过 $? 获取,可以不写return,不写相当于最后一条命令结果,值只能是 0-255

例如求和:

#!/bin/bash
sum() {
    s=$(($1+$2))
    echo "和为$s"
}

read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b
sum $a $b

返回的值不能过大,过大将会溢出,可以使用 echo 模拟返回的效果

#!/bin/bash
sum() {
    s=$(($1+$2))
    echo $s
}

read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b

result=$(sum $a $b)

echo "两数之和为:$result"

exit 代表退出,后边跟着一个返回值,依旧是0-255:

#!/bin/bash
sum() {
    s=$(($1+$2))
    echo $s
}

if [ $# -ne 2 ] 
then 
    echo "需要两个参数,已提供:$#个"
    exit 1
fi

result=$(sum $1 $2)

echo "两数之和为:$result"

cut

可以用来分割字符,可以用在文件和管道

cat /etc/passwd | cut -d "单个分隔符" -f 第几列

例如

➜  shell cat cut.txt    
小红:女
小航:男
小那:女
小工:男
小路:女
小明:男
➜  shell cut -d ':' -f 1 cut.txt 
小红
小航
小那
小工
小路
小明
➜  shell 
➜  shell cat cut.txt | cut -d ':' -f 1
小红
小航
小那
小工
小路
小明

Q.E.D.


念念不忘,必有回响。