shell简介

Shell 诞生于 Unix,是与 Unix/Linux 交互的工具。Shell虽然是Unix的第一个脚本语言,但它是相当优秀的。它结合了延展性与效率,持续保有独具的特色,并不断的被改良,使它多年来能与那些花招很多的脚本语言保持抗衡。

Shell需要依赖其他程序才能完成大部分的工作,这或许是它的缺陷,但它不容置疑的长处是:简洁的脚本语言标记方式,而且比C语言编写的程序执行更快、更有效率。

Shell 是将内核、程序和用户连接了起来的软件

Shell 本身支持的命令并不多,但是它可以调用其他的程序,每个程序就是一个命令,这使得 Shell 命令的数量可以无限扩展,其结果就是 Shell 的功能非常强大。

shell是一种脚本语言,因此需要编译成二进制的形式才可以被计算机执行。

几种常见的Shell:sh、bash、csh、tcsh、ash。其中默认的是bash,使用 echo $SHELL 查看默认的shell。 SHELL 是 Linux 系统中的环境变量,它指明了当前使用的 Shell 程序的位置,也就是使用的哪个 Shell。

对于普通用户,Base shell 默认的提示符是美元符号$;对于超级用户(root 用户),Bash Shell 默认的提示符是井号#

echo 是一个输出命令,可以用来输出数字、变量、字符串等;

bash shell中变量都是字符串类型,使用变量在变量名前加 $,变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界

单双引号的区别:单引号’ ‘包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。双引号” “包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。

使用 $(变量名or内容) 读取变量的值or内容。

声明只读变量 readonly 变量名,删除变量 unset 变量名

变量类型
运行shell时,会同时存在三种变量:

1) 局部变量
局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2) 环境变量
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
3) shell变量
shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

特殊变量列表
| 变量 | 含义 |
| :—: | :——————————————————————————————: |
| $0 | 当前脚本的文件名 |
| $n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 |
| $# | 传递给脚本或函数的参数个数。 |
| $* | 传递给脚本或函数的所有参数。 |
| $@ | 传递给脚本或函数的所有参数。被双引号(“ “)包含时,与 $* 稍有不同,下面将会讲到。 |
| $? | 上个命令的退出状态(上一个命令执行后的返回结果),或函数的返回值。 |
| $$ | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |

命令行参数

命令行参数
运行脚本时传递给脚本的参数称为命令行参数。命令行参数用 $n 表示,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

请看下面的脚本:

1
2
3
4
5
6
7
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"

运行结果:

1
2
3
4
5
6
7
$./test.sh Zara Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2

注:$* 和 $@ 的区别

转义字符 含义
\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键)
\v 垂直制表符

可以使用 echo 命令的 -E 选项禁止转义,默认也是不转义的;使用 -n 选项可以禁止插入换行符。

命令替换
命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。
命令替换的语法:command

将命令执行结果保存在变量中:

1
2
3
4
5
6
7
#!/bin/bash
DATE=`date`
echo "Date is $DATE"
USERS=`who | wc -l`
echo "Logged in user are $USERS"
UP=`date ; uptime`
echo "Uptime is $UP"

运行结果:

1
2
3
4
Date is Thu Jul  2 03:59:57 MST 2009
Logged in user are 1
Uptime is Thu Jul 2 03:59:57 MST 2009
03:59:57 up 20 days, 14:03, 1 user, load avg: 0.13, 0.07, 0.15

变量替换
变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值

可以使用的变量替换形式:
| 形式 | 说明 |
| :————-: | :—————————————————————————————————————————————————————: |
| ${var} | 变量本来的值 |
| ${var:-word} | 如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。 |
| ${var:=word} | 如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。 |
| ${var:?message} | 如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。 |
| ${var:+word} | 如果变量 var 被定义,那么返回 word,但不改变 var 的值。 |

shell运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。

算数运算符

运算符 说明 举例
+ 加法 expr $a + $b 结果为 30。
- 减法 expr $a - $b 结果为 10。
* 乘法 expr $a \* $b 结果为 200。
/ 除法 expr $b / $a 结果为 2。
% 取余 expr $b % $a 结果为 0。
= 赋值 a=$b 将把变量 b 的值赋给 a。
== 相等。用于比较两个数字,相同则返回 true。 [ $a == $b ] 返回 false。
!= 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。

关系运算符列表

运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 true。
-ne 检测两个数是否相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。

布尔运算符列表

运算符 说明 举例
! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
-o 或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a 与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。

字符串运算符列表

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否为0,不为0返回 true。 [ -z $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。

文件测试运算符

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是具名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

字符串

除了单双引号的区别外,还有:
拼接字符串

1
2
3
4
your_name="qinjx"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1

获取字符串长度

1
2
string="abcd"
echo ${#string} #输出 4

提取子字符串

1
2
string="alibaba is a great company"
echo ${string:1:4} #输出liba

查找子字符串

1
2
string="alibaba is a great company"
echo `expr index "$string" is`

数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。

定义数组

1
2
3
4
5
6
7
8
9
10
11
12
array_name=(value0 value1 value2 value3)
# 或者
array_name=(
value0
value1
value2
value3
)
# 单独定义
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

使用数组

1
2
3
4
valuen=${array_name[2]}
# 使用@ 或 * 可以获取数组中的所有元素,例如:
${array_name[*]}
${array_name[@]}

获取数组长度

1
2
3
4
5
6
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}

输出语句

echo和printf(C语言中的printf,只是没有括号,其他不变),printf是echo的升级版。

条件语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
echo "a is equal to b"
elif [ $a -gt $b ]
then
echo "a is greater than b"
elif [ $a -lt $b ]
then
echo "a is less than b"
else
echo "None of the condition met"
fi

test命令

shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

数值测试

1
2
3
4
5
6
7
8
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo 'The two numbers are equal!'
else
echo 'The two numbers are not equal!' # 输出结果
fi

比较运算符它不香吗??

字符串测试

1
2
3
4
5
6
7
8
num1=100
num2=100
if test num1=num2
then
echo 'The two strings are equal!'
else
echo 'The two strings are not equal!'
fi

文件测试

1
2
3
4
5
6
7
cd /bin
if test -e ./bash
then
echo 'The file already exists!'
else
echo 'The file does not exists!'
fi

case命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo 'Input a number between 1 to 4'
echo 'Your number is:\c'
read aNum
case $aNum in
1) echo 'You select 1'
;;
2) echo 'You select 2'
;;
3) echo 'You select 3'
;;
4) echo 'You select 4'
;;
*) echo 'You do not select a number between 1 to 4'
;;
esac

取值后面必须为关键字 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。;; 与其他语言中的 break 类似,意思是跳到整个 case 语句的最后。

取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

for循环

格式

1
2
3
4
5
6
7
for 变量 in 列表
do
command1
command2
...
commandN
done

列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。

in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。

显示主目录下以 .bash 开头的文件:

1
2
3
4
5
#!/bin/bash
for FILE in $HOME/.bash*
do
echo $FILE
done

运行结果:

1
2
3
4
/root/.bash_history
/root/.bash_logout
/root/.bash_profile
/root/.bashrc

参考文献

评论

载入天数...载入时分秒...