全栈工程师开发手册 (作者:栾鹏)
架构系列文章
什么是shell编程
高大上的解释,往往让人摸不住头脑。一句话概括就是:shell编程就是对一堆Linux命令的逻辑化处理。
为什么要会shell编程
就是批处理动作,解放双手,避免重复性劳动。
第一个shell程序
#!/bin/bash # 这句话表示用linux指定去解析文本内容
#第一个shell小程序
echo hello world!
第一行表示我们选择使用bash shell。shell中#符号表示注释。shell的第一行比较特殊,一般都会以#!开始来指定使用的shell类型。在linux中,除了bash shell以外,还有很多版本的shell, 例如zsh、dash等等…不过bash shell还是我们使用最多的。
第二行以#符号开始,表示本行是注释,运行的时候是不会运行本行的。
第三行中的echo是linux中的输出命令,该行的意思很明显的就是输出hello world!
运行第一个shell程序
新创建一个文件(hello_world.sh), 然后将以上代码复制到此文件中,然后需要赋予此文件的可执行权限。
chmod +x hello_world.sh
最后执行:
./hello_world.sh
在linux中,后缀名几乎是可以任意的或者没有后缀名,一般将shell保存为xxx.shell是为了看起来更直观。
如果直接执行hello_world.sh,这时会默认从$PATH环境变量中去寻找,这时,由于我们为将此文件配置在环境变量中,因此会找不到。所以,我们用了"."这个符号,表示从当前目录找。
除了以上执行方法,我们还可以直接指定shell来运行:
/bin/sh hello_world.sh
变量
shell编程中分为两种变量,第一种是我们自己定义的变量(自定义变量),第二种是Linux已定义的环境变量(环境变量, 例如:$PATH, $HOME
等…, 这类变量我们可以直接使用)。
#!/bin/bash
#使用环境变量
echo $PATH
#自定义变量hello
hello="hello world"
echo $hello
以上演示了自定义变量和系统环境变量的用法,使用很简单,就是使用$
符号加上变量名就行了。记住:定义变量不用$
符号,使用变量要加$
就行了。
在第5行中,我们在自定义变量时,使用了双引号,在shell编程中, 如果变量出现空格或者引号,那么也必须加引号, 否则就可以省略。
还有一点需要注意,定义变量的时候,“=”左右千万不要有空格啊。
使用变量
your_name="qinjx"
echo $your_name
echo ${your_name}
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
将linux命令执行结果赋值给变量
#!/bin/bash
path=$(pwd)
files=`ls -al`
echo current path: $path
echo files: $files
以上2行和第3行分别演示了两种方式来将Linux命令执行结果保存到变量。
第2行将pwd执行结果(当前所在目录)赋值给path变量。
第3行将ls -al命令执行结果(列出当前目录下所有的文件及文件夹)赋值给变量
字符串
字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
your_name="runoob"
# 使用双引号拼接
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
输出结果为:
hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !
获取字符串长度
string="abcd"
echo ${#string} #输出 4
提取子字符串
以下实例从字符串第 2 个字符开始截取 4 个字符:
string="runoob is a great site"
echo ${string:1:4} # 输出 unoo
查找子字符串
查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):
string="runoob is a great site"
echo `expr index "$string" io` # 输出 4
注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。
Shell 文件接收参数
echo "执行的文件名:$0"; # $0 为执行的文件名
echo "参数个数:$#"; # 传递到脚本的参数个数
echo "第一个参数为:$1"; # 第1个输入参数
echo "第二个参数为:$2"; # 第2个输入参数
for i in "$*"; do # $*以一个单字符串显示所有向脚本传递的参数。$@可以获取所有传入参数
echo $i
done
Shell 流程控制
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((i=0;i<20;i++));
do
curl 127.0.0.1:9200/_bulk?pretty --data-binary @data/data$i.json
echo $i成功
done
或者
for i in $(seq 0 20)
do
curl 127.0.0.1:9200/_bulk?pretty --data-binary @data/data$i.json
echo $i成功
done
while 语句
while condition
do
command
done
Shell case语句
aNum=1
case aNum in
1)
command1
command2
commandN
;;
2)
command1
command2
commandN
;;
esac
Shell 数组
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小(与 PHP 类似)。
与大部分编程语言类似,数组元素的下标由0开始。
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
数组名=(值1 值2 ... 值n)
my_array=(A B "C" D)
echo "第一个元素为: ${my_array[0]}"
echo "第二个元素为: ${my_array[1]}"
echo "第三个元素为: ${my_array[2]}"
echo "第四个元素为: ${my_array[3]}"
echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"
echo "数组元素个数为: ${#my_array[*]}"
echo "数组元素个数为: ${#my_array[@]}"
还可以单独定义数组的各个分量:
my_array[0]=value0
shell 数组遍历的3种方法
标准的for循环
for(( i=0;i<${#array[@]};i++)) do
#${#array[@]}获取数组长度用于循环
echo ${array[i]};
done;
for … in
遍历(不带数组下标):
for element in ${array[@]}
#也可以写成for element in ${array[*]}
do
echo $element
done
遍历(带数组下标):
for i in "${!arr[@]}";
do
printf "%s\t%s\n" "$i" "${arr[$i]}"
done
While循环法:
i=0
while [ $i -lt ${#array[@]} ]
#当变量(下标)小于数组长度时进入循环体
do
echo ${ array[$i] }
#按下标打印数组元素
let i++
done
算术运算符
假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | `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。 |
#!/bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a 等于 b"
fi
if [ $a != $b ]
then
echo "a 不等于 b"
fi
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
-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。 |
#!/bin/bash
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi
布尔运算符
变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 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。 |
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi
逻辑运算符
变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 \|\| $b -gt 100 ]] 返回 true |
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
字符串运算符
假定变量 a 为 “abc”,变量 b 为 “efg”:
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否为0,不为0返回 true。 | [ -n $a ] 返回 true。 |
str | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a 等于 b"
else
echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串长度为 0"
else
echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
echo "-n $a : 字符串长度不为 0"
else
echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
echo "$a : 字符串不为空"
else
echo "$a : 字符串为空"
fi
文件测试运算符
假设file="/var/www/runoob/test.sh
"
运算符 | 说明 | 举例 |
---|---|---|
-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。 |
打印输出
Shell echo命令
显示普通字符串
echo "It is a test"
echo It is a test # 双引号完全可以省略
echo "\"It is a test\"" # 显示转义字符
# 显示变量
name="luanpeng"
echo "$name It is a test"
echo -e "OK! \n" # -e 开启转义
echo -e "OK! \c" # -e 开启转义 \c 打印后不换行
echo "It is a test" > myfile # 显示结果定向至文件
echo `date` # 显示命令执行结果
Shell printf 命令
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
%s %c %d %f都是格式替代符
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中.2指保留2位小数。
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
我们可以用函数来测试命令的运行结果
#!/usr/bin/env bash
isok(){
if [ $1 -eq 0 ]
then
echo $2 sucess # sucess=0
else
echo $2=============================失败
fi
}
apt-get install vim
echo $?
isok $? "apt-get install vim"
Shell 文件引用
#使用 . 号来引用test1.sh 文件
. ./test1.sh
# 或者使用以下包含文件代码
# source ./test1.sh
Shell脚本中调用另外一个脚本的方法
在Linux平台上开发,经常会在console(控制台)上执行另外一个脚本文件,经常用的方法有:./my.sh 或 source my.sh 或 . my.sh;这三种方法有什么不同呢?我们先来了解一下在一个shell脚本中如何调用另外一个shell脚本,其方法有 fork exec source。
1、fork ( /directory/script.sh) :
如果shell中包含执行命令,那么子命令并不影响父级的命令,在子命令执行完后再执行父级命令。子级的环境变量不会影响到父级。
fork是最普通的, 就是直接在脚本里面用/directory/script.sh来调用script.sh这个脚本. 运行的时候开一个sub-shell执行调用的脚本,sub-shell执行的时候,parent-shell还在。
sub-shell执行完毕后返回parent-shell. sub-shell从parent-shell继承环境变量.但是sub-shell中的环境变量不会带回parent-shell
使用时直接在shell文档中写另一个shell脚本的地址就行了。
/lp/hadoop/hadoop-2.7.3/sbin/start-all.sh
2、exec (exec /directory/script.sh):
执行子级的命令后,不再执行父级命令。
exec与fork不同,不需要新开一个sub-shell来执行被调用的脚本. 被调用的脚本与父脚本在同一个shell内执行。但是使用exec调用一个新脚本以后, 父脚本中exec行之后的内容就不会再执行了。这是exec和source的区别
3、source (source /directory/script.sh):
执行子级命令后继续执行父级命令,同时子级设置的环境变量会影响到父级的环境变量。
与fork的区别是不新开一个sub-shell来执行被调用的脚本,而是在同一个shell中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中得到和使用.
以上三种就是调用shell脚本的不同方法,./my.sh即是fork的方法,source my.sh和. my.sh(点加空格加脚本文件)既是source的方法。
在linux系统上,搭建嵌入式开发平台,在交叉编译代码之前,都需要执行脚本设置环境变量,切记需要使用sourc 或 点的方式执行shell脚本,原因如上。
Linux shell 中 ( ) ‘ ‘ , () ` `, ()‘‘,{},$[] $(()),[ ] (( )) [[ ]]作用与区别
参考:https://blog.csdn.net/x1269778817/article/details/46535729
Linux 命令行 &&与||
参考:https://www.jianshu.com/p/25b0d6c9dc9f
参考:http://c.biancheng.net/view/735.html
Linux 下以其他用户身份运行程序—— su、sudo、runuser
参考:https://www.cnblogs.com/bodhitree/p/6018369.html