【前言】shell俗称'『壳』,多么中二的名字。脚本就是脚本,它能帮你干很多事情。中二的不是他的名字,是看待名字的人,像『宇宙大将军』这样的称号,现代人又是这样看待的呢?
介绍
其实它也是一门语言,而它的特长就在脚本上。
Shell脚本一般在Linux等类UNIX系统上都可以运行,而在windows上需要安装环境来运行,其实安装GIT这款软件,就能支持部分linux命令
这是常见的shell环境
• Bourne Shell(/usr/bin/sh或/bin/sh)
• Bourne Again Shell(/bin/bash)
• C Shell(/usr/bin/csh)
• K Shell(/usr/bin/ksh)
• Shell for Root(/sbin/sh)
环境的选择这里就不讲,默认以及最常用的就是Bourne Again Shell,也是Linux系统默认的shell
他有两种执行模式:
1,将其更改为执行文件 chmod +x filename.sh
./filename.sh
2,sh filename.sh
---
其实写这些大多都能够在网上查询的到,云大脑确实可以作为解决问题的方案之一,但是我们不能只做云大脑,任何都靠搜索引擎来补充资源。其实单看这一篇文章也不能一下子成为大佬,这是我所不能成就的,更多的还是不够精细,但是见长还是得一步一步慢慢了解。
---
变量
作为一门语言,基础框架是学习 变量,数据类型,运算符,函数,IO,流程控制,循环往深一点就是操作数据库,操作文件,调用三方,通信等更高级一点就是建立模块供其它调用
shell也是大致如此,变量的命名:你可以这样定义
name="you contents"
// 命名规则和其它大差不差
// 使用变量
echo $name
// 或者
echo ${name}
shell也可以传参,案例就是 ./filename.sh 1 2 3
$0 是本文件名
参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
shell数组
array_name=(value1 ... valuen)
my_array=(A B "C" D)
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
array_name[3]=value3
> A B C D
使用@ 或 * 可以获取数组中的所有元素,例如:
echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"
> 数组的元素为: A B C D
获取数组长度的方法与获取字符串长度的方法相同,例如:
echo "数组元素个数为: ${#my_array[*]}"
echo "数组元素个数为: ${#my_array[@]}"
> 数组元素个数为: 4
shell 运算符
• 算数运算符
• 关系运算符
• 布尔运算符
• 字符串运算符
• 文件测试运算符
前面三个可能比较简单,毕竟大家都是会java或者JavaScript的嘛,怎么不济也会PHP或者python,和这些语言的运算符基本上一样
val=`expr 2 + 2`
echo "两数之和为 : $val"
> 两数之和为 : 4
算术运算符
运算符 说明 举例
+ 加法 `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。
乘号是比较特殊的,需要转义处理
在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "" 。
关系运算符
运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
-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。
逻辑运算符
运算符 说明 举例
&& 逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true
以上运算符写法就是这些,使用的语法也不难,后面会联系分支流程控制语句做出例子
以下就是比较特殊的运算符,不同语言可能会不同
字符串运算符
运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否不为 0,不为 0 返回 true。 [ -n "$a" ] 返回 true。
$ 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。
shell脚本操作文件是很常有的,接下来介绍的是
文件测试运算符
操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $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。
• -S: 判断某文件是否 socket。
• -L: 检测文件是否存在并且是一个符号链接。
运算符用于计算比较判断等等,比较基础,会的越多,功能就越全
输出语句:echo
1,普通输出
echo "It is a test"
2,转义输出
echo ""It is a test""
3,显示变量
read name
echo "$name It is a test"
这个意思有点类似python的input()函数
4,换行显示
echo -e "OK! \n" # -e 开启转义
echo "It is a test"
> OK!
It is a test
5,显示不换行
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
> OK! It is a test
6,显示结果定向至文件
echo "It is a test" > myfile
这个我感觉还是挺好玩的,>: 表示写入文件,并覆盖原来的内容 >>: 写入文件,追加原来的内容
7,原样输出字符串,不进行转义或读取变量(用单引号)
echo '$name"'
> $name"
欸!还有点像PHP啊
8,显示命令执行结果
echo `date`
> Thu Jul 24 10:08:46 CST 2014
这个是反引号,也是和PHP有点像,可以执行脚本命令用的
输出 printf命令
这个命令对于学过C语言的再熟悉不过了,格式化输出
• printf 命令模仿 C 程序库(library)里的 printf() 程序。
• printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。
• printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n。
printf format-string [arguments...]
format-string : 为格式化控制字符串
arguments : 为参数列表
例:
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
>
姓名 性别 体重kg
郭靖 男 66.12
杨过 男 48.65
郭芙 女 47.99
%s %c %d %f都是格式替代符
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中.2指保留2位小数。
printf的转义序列
序列 说明
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
\f 换页(formfeed)
\n 换行
\r 回车(Carriage return)
\t 水平制表符
\v 垂直制表符
\ 一个字面上的反斜杠字符
\ddd 表示1到3位数八进制值的字符。仅在格式字符串中有效
\0ddd 表示1到3位的八进制值字符
test
shell还有一个命令可以测试,就是test
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。
数值测试
参数 说明
-eq 等于则为真
-ne 不等于则为真
-gt 大于则为真
-ge 大于等于则为真
-lt 小于则为真
-le 小于等于则为真
因为比较少见,所以给个例子
num1=100
num2=100
if test $num1 -eq $num2
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
> 两个数相等!
代码中的 [] 执行基本的算数运算
a=5
b=6
result=$[a+b]
echo "result 为: $result"
> result 为: 11
字符串测试
参数 说明
= 等于则为真
!= 不相等则为真
-z 字符串 字符串的长度为零则为真
-n 字符串 字符串的长度不为零则为真
num1="老干妈"
num2="老千妈"
if test $num1 = $num2
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
> 两个字符串不相等!
当然shell经常操作文件
文件测试
参数 说明
-e 文件名 如果文件存在则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-d 文件名 如果文件存在且为目录则为真
-f 文件名 如果文件存在且为普通文件则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真
cd /bin
if test -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
> 文件已存在!
另外,Shell还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:"!"最高,"-a"次之,"-o"最低。例如:
if test -e ./notFile -o -e ./bash
then
echo '至少有一个文件存在!'
else
echo '两个文件都不存在'
fi
> 至少有一个文件存在!
shell流程控制
shell脚本和其它语言不同的事他的流程控制不可为空,不像python那样还可以使用pass来占个位置,shell脚本如果不需要就不用写
先说最熟悉的if else
if else
if:
语法格式:
if condition
then
command1
command2
...
commandN
fi一行式:
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
有时候我们会在命令行中使用shell脚本,使用一行式较简便
结尾一般是倒着写的单词,如 if 结尾就用 fi
if else
语法格式:
if condition
then
command1
command2
...
commandN
else
command
fi
if else-if else
语法格式:
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
for
语法格式:
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
例:
for var in 1 2 3 4 5
do
echo "value is:" $var
done
>
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
while
语法格式:
while condition
do
command
done
例:
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
>
1
2
3
4
5
let 命令:执行一个或多个表达式
如果你想体验java或者python的哪种无限输入的感觉,shell就能帮你实现
echo '按下 <CTRL-D> 退出'
echo -n '输入你想点赞的理由: '
while read FILM
do
echo "是的!$FILM 是一个好理由"
done
>
按下 <CTRL-D> 退出
输入你想点赞的理由:帅
是的!帅 是一个好理由
下面教你如何无限循环:无限月读 [無限月読]
无线循环可不是闹着玩的,小心内存爆掉哦!
1 ->
while :
do
command
done
2 ->
while true
do
command
done
3 ->
for (( ; ; ))
下面介绍几个可能在别的语言中有的,但是在php中没有的循环
until循环
顾名思义就是到……结束
until 循环执行一系列命令直至条件为 true 时停止。
是不是和while语句相反呢,欸!人家就是这么特立独行
语法格式:
until condition
do
command
done
例:
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
>
0
1
2
3
4
5
6
7
8
9
case
语法格式:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
是不是和switch case有点像,好吧其实差不多啦
例:
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
>
输入 1 到 4 之间的数字:
你输入的数字为:
3
你选择了 3
它是使用‘;;’来结束,其实PHP中你可以使用无数个‘;’反正效果都一样
*号有点类似于default
看它的结束符 esac真别扭,哈,其实就是倒过来了。
跳出循环
循环只是过程,我们要的是结果,淦
break
效果就是你们所知道那样,跳出,终止循环
continue
跳出本次循环,不执行后面代码
shell 函数
连C语言都有函数,我shell脚本当然也得有,对吧
用户可以自定义函数
语法格式:
[ function ] funname [()]
{
action;
[return int;]
}
定义方法有两种:
1,function func()
2,func()
你觉得哪个方便
和其它语言函数一样可以有返回值,用return就可以了
例:
demoFun(){
echo "这是我的第一个 shell 函数!"
}
echo "-----函数开始执行-----"
demoFun
echo "-----函数执行完毕-----"
>
-----函数开始执行-----
这是我的第一个 shell 函数!
-----函数执行完毕-----
函数也可以有参数,但是shell脚本和其它语言不一样的是,它的参数,不是写在括号中,和命令行传参一样
例:
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
>
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
特殊字符用来处理参数
参数处理 说明
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
shell输入输出重定向
还记得之前用到过的echo filename > newfile吗,有点类似了
命令 说明
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。
需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。
Here Document
PHP也有这个,主要是写一些文本文件,或者html什么的
shell脚本和PHP的用法类似
例:
cat << EOF
欢迎来到
extend
shell
EOF
>
欢迎来到
extend
shell
/dev/null 文件
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
如果希望屏蔽 stdout 和 stderr,可以这样写:
command > /dev/null 2>&1
注意:0 是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。
这里的 2 和 > 之间不可以有空格,2> 是一体的时候才表示错误输出。
shell文件包含
和其它语言一样,shell脚本也可以引入外部文件,这听上去是python的特长
语法格式:
. filename
或
source filename
类似于php的引入
举个例子:
创建一个文件叫lib.sh
name = "小花"
password = "9994"
我们在第二个文件中引用
controller.sh
. ./lib.sh
echo "用户名:$name"
echo "密码:$password"
运行controller.sh
chmod +x ccontroller.sh
./controller.sh
>
用户名:小花
密码:9994
旅途很短暂呐!想必痛苦的事情还在后头呢~
时光不暇,匆匆而逝 谨以此篇,纪念过往
【声明】本篇是纯个人编辑,创造,知识点及表格等基础知识部分来源于菜鸟教程,整合知识点及讲解全部由本人亲手纂写。
.扩展
==================== 以下为shell脚本学习扩展
• 使用cd无效问题
在shell脚本中,如果使用cd ./path,执行shell脚本是不会进入path目录的,原因是shell脚本会创建一个子shell,并在子shell中逐个执行脚本中的指令; 而子shell中从父shell中继承了环境变量,但是执行后不会改变父shell的环境变量;如果想要代码中切换目录的操作生效,只需要通过source 命令执行即可:
设有一个名叫this.sh的shell脚本,内容如下
cd ./path
> sh this.sh
...... 好尴尬,什么都没执行
解决方法:source ./this.sh 或 . ./this.sh
运行
咦~好神奇!
• base_path=$(cd $(dirname $0); pwd)
项目中很多地方都用到了这个,通常都是广义上的第一行,解释一下这一条语句的神奇所在
在linux的shell中经常需要进入脚本当前所在的目录,以其为基准使用相对路径,那么怎样获取到这个路径呢?
linux的shell中并没有一个变量能直接代表这个路径,需要自己使用命令来构造。
path=$(cd`dirname $0`;pwd)
这条简单的命令就可以进入当前的路径,并且将路径值存在变量里。
- 首先是使用反引号包起来的dirname $0命令。使用反引号代表执行其中的命令并返回命令结果。而$0代表脚本的文件名。这条指令就可以得到脚本的路径。
- 然后使用dirname通过文件名获取路径,因为$0并不是绝对路径,所以使用dirname得到的也不是绝对路径。这时使用cd进入,然后再使用pwd命令得到当前路径的绝对路径。
• 解答为什么函数return后如何接收问题
定义一个函数
func()
{
return 100
}
func
echo $?
运行结果
> 100
• export
在shell中执行程序时,shell会提供一组环境变量。export可新增,修改或删除环境变量,供后续执行的程序使用。同时,重要的一点是,export的效力仅及于该次登陆操作。注销或者重新开一个窗口,export命令给出的环境变量都不存在了。
该命令的语法如下:
export [-fnp][变量名称]=[变量设置值]
其中:
○ -f 代表[变量名称]中为函数名称。
○ -n 删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。
○ -p 列出所有的shell赋予程序的环境变量。
你可以只打出export来查看当前的所有环境变量。如果你要在某个环境变量(比如PATH)中加入一些新的路径(如/bin/bash),可以使用如下命令格式
export PATH=/bin/bash:$PATH
• ls > log 2>&1
这是什么意思呢
ls的内容重定向到log中了,2是标准错误,1是标准输出,0是标准输入,0是键盘输入,1和2都是输出,以上意思就是错误不输出到屏幕,重定向到文件
a = 'hello world'
echo $a