『简介』
Shell指的是一种应用程序,这个应用程序能够直接和系统内核直接沟通,然后让内核来操作系统的硬件。狭义的Shell可能指的是命令列下的软件,好像平时用的bash、zsh等,广义的Shell还包括图形界面的软件,因为图形界面其实都可以操作各种应用程序来呼叫内核来工作。
本文只会记录一下基本语法和自己的练习记录,用于回忆,希望对您有帮助。
『语法』
基本结构
#!/bin/bash
# Author:
# Gavinjou大笨象
# Date:
# 2019-05-02
# Description:
# 基本结构
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
echo -e "Hello World! \a \n"
exit 0
- 第一行【#!/bin/bash】告诉这个script要使用哪个Shell:
因为当前使用的是bash,所以必须使用【#!/bin/bash】。当这个脚本被执行时,他就能载入bash的相关环境。这行是必须的,因为有可能其他Shell的语法有区别,所以指定Shell很关键 - 程序内容:
除了第一行是声明Shell外,其他【#】都是注解,所以第二行的注解最好说明该Shell的用途包括:内容与功能,版本资讯,作者联系方式,建档日期,历史记录等 - 环境变量声明
建议还是将运行环境变量设定好,因为可以下达一些【外部指令】的时候,不用写绝对路径。如果只用【内建指令】其实可以不写,查看命令是否为【内建命令】可以使用type
指令 - 主程部分
就是那个【echo】那句话 - 执行结果返回值
就是那个【exit】语句,正常执行的话,最好还是返回一个值
变量
基本变量定义:
#!/bin/bash
myname="Gavinjou大笨象" #基本变量定义,等号不能有空格
echo -e "${myname}" #输出时推荐都用花括号包裹
exit 0
输出结果
Gavinjou大笨象
只读变量:
#!/bin/bash
myname="Gavinjou大笨象"
readonly myname #只读变量
echo -e "${myname}"
exit 0
输出结果
Gavinjou大笨象
删除变量:
#!/bin/bash
myname="Gavinjou大笨象"
echo -e "${myname}"
unset myname # 删除变量
echo -e "!-> ${myname}"
exit 0
输出结果
Gavinjou大笨象
!->
字符串变量:
#!/bin/bash
# 在shell中默认类型是字符串
myname1="Gavinjou大笨象" #双引号字符串
myname2='Gavinjou大笨象' #单引号字符串
# 双引号和单引号区别
echo -e "${myname1} ${myname2}"
echo -e '${myname1} ${myname2}'
exit 0
输出结果
Gavinjou大笨象 Gavinjou大笨象
${myname1} ${myname2}
拼接字符串:
#!/bin/bash
myname1="Gavinjou大笨象"
myname2='hello'
greeting1="${myname2} ${myname1}\n" #双引号拼接
greeting2='${myname2} ${myname1}\n' #单引号拼接
echo -e ${greeting1} ${greeting2}
exit 0
输出结果
hello Gavinjou大笨象
${myname2} ${myname1}
获取字符串长度:
#!/bin/bash
myname1="Gavinjou大笨象"
echo -e ${#myname1} #获取长度
exit 0
输出结果
17
提取子字符串:
#!/bin/bash
myname="Gavinjou大笨象"
echo -e ${myname:1:4} # 提取字符串
exit 0
输出结果
avin
查找子字符串:
#!/bin/bash
myname="Gavinjou大笨象"
echo -e `expr index ${myname} jou` # 查找jou的位置
exit 0
输出结果
6
数组:
#!/bin/bash
array1=('G' 'a' 'v' 'i' 'n') # 数组定义第一种形式
# 数组定义第二种形式
array2[0]='G'
array2[1]='a'
array2[2]='v'
array2[3]='i'
array2[4]='n'
array2[10]='test' #可以单独定义分量
# 读取数组
echo -e "读取:${array1[0]} - ${array2[0]}\n"
# 获取所有元素
echo -e "所有元素:${array1[@]}\n"
# 取得数组元素个数
echo -e "array2数组元素个数:${#array2[@]}" # 第一种方式
echo -e "array1数组元素个数:${#array1[*]}" # 第二种方式
# 取得数组单个元素的长度
echo -e "array2的0号元素长度:${#array2[0]}"
exit 0
输出结果
读取:G - G
所有元素:G a v i n
array2数组元素个数:6
array1数组元素个数:5
array2的0号元素长度:1
注释:
#!/bin/bash
# 单行注释
:<<EOF # EOF可以换其他字符,推荐EOF
多行注释
EOF
echo -e "test"
exit 0
输出结果
test
参数传递
参数传递:
#!/bin/bash
# 执行脚本命令
# 第一种方式:sh sh01.sh 1 2 3 4
# 第二种方式:./sh01.sh 1 2 3 4
# 参数传递
echo "传递参数实例"
echo "执行的文件名:$0"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "第三个参数为:$3"
exit 0
输出结果
传递参数实例
执行的文件名:sh01.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
特殊字符用法
#!/bin/bash
# 执行脚本命令
# 第一种方式:sh sh01.sh 1 2 3 4
# 第二种方式:./sh01.sh 1 2 3 4
# $* 与 $@ 区别
echo -e '$*执行'
k=1
for val in "$*";
do
echo "$val - 次数:$k"
k=$((k + 1))
done
echo -e '$@执行'
k=1
for val in "$@";
do
echo "$val - 次数:$k"
k=$((k + 1))
done
exit 0
输出结果
$*执行
1 2 3 - 次数:1
$@执行
1 - 次数:1
2 - 次数:2
3 - 次数:3
基本运算符
算术运算符:
#!/bin/bash
a=10
b=20
val1=`expr $a \* $b` #形式一,乘法要加斜杠,其他运算符不用加斜杠。
val2=$(($a * $b)) #形式二,其他运算符都不用加斜杠
echo -e "a * b = ${val1} \n"
echo -e "a * b = ${val2} \n"
if [ $a != $b ]; # 其他比较运算符也是
then
echo "a != b"
fi
exit 0
输出结果
a * b = 200
a * b = 200
a != b
关系运算符:
#!/bin/bash
# 关系运算符只支持数字,除非字符串是数字
a=10
b=20
if [ $a -eq $b ] #其他关系运算符也是如此
then
echo "$a -eq $b :等于"
else
echo "$a -eq $b :不等于"
fi
exit 0
输出结果
10 -eq 20 :不等于
布尔运算符:
#!/bin/bash
a=10
b=20
if [ $a -lt $b -o $a -eq $b ] #其他布尔运算符也是如此
then
echo "符合要求"
else
echo "不符合要求"
fi
exit 0
输出结果
符合要求
逻辑运算符:
#!/bin/bash
a=10
b=20
if [[ $a -gt $b || $a -eq $b ]] #其他逻辑运算符也是如此
then
echo "符合要求"
else
echo "不符合要求"
fi
exit 0
输出结果
不符合要求
字符串运算符:
#!/bin/bash
a="a"
b="b"
if [ $a = $b ] #其他字符串运算符也是如此
then
echo "等于"
else
echo "不等于"
fi
exit 0
输出结果
不等于
文件测试运算符:
#!/bin/bash
# 生成文件 touch test.sh
# 执行脚本 ./sh04.sh
file="./test.sh"
if [ -r $file ] # 其他文件运算符也是如此
then
echo "文件可读"
else
echo "文件不可读"
fi
exit 0
输出结果
文件可读
ECHO命令
echo命令:
#!/bin/bash
# 显示普通字符串
echo "gavinjou" # 推荐
echo gavinjou # 可以省略,但是不推荐
# 显示转义字符
echo "\"gavinjou\"" # 推荐
echo \"gavinjou\" # 可以省略,但是不推荐
# 显示变量
name="test"
echo "${name}"
# 显示换行
echo -e "test \n" #-e开启转义
echo "test \n" #不开启转义
# 显示不换行
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
# 显示结果定向至文件
echo "It is a test" > myfile
# 原样输出字符串,不进行转义或取变量(用单引号)
echo '$name\"'
# 显示命令执行结果
echo `date`
exit 0
输出结果
gavinjou
gavinjou
"gavinjou"
"gavinjou"
test
test
test \n
OK! It is a test
$name\"
Thu May 2 03:02:29 UTC 2019
PRINTF命令
和C语言基本一样
printf命令:
#!/bin/bash
# 简单输出
printf "Hello World\n"
# 对齐和格式化输出
printf "%-10s %8s %-4s\n" 姓名 性别 体重kg
# 双引号
printf "%d %s\n" 1 "abc"
# 单引号
printf '%d %s\n' 1 "abc" #和双引号效果一样
# 无引号
printf %s abcdef # 不推荐
# 只指定一个参数,格式会重用,但这些技巧都不推荐
printf %s !abc def
# 如果没有参数 %s用NULL %d用0代替
printf "%s and %d \n"
exit 0
输出结果
Hello World
姓名 性别 体重kg
1 abc
1 abc
abcdef!abcdef
TEST命令
数值测试:
#!/bin/bash
# test可以用于检查某个条件是否成立,
# 它可以进行数值、字符和文件三个方面的测试。
num1=100
num2=100
# 换成字符串形式也可以执行
# num1="100"
# num2="100"
if test $[num1] -eq $[num2];
then
echo "相等"
else
echo "不相等"
fi
# []代表执行基本的算数运算
#不建议用这种方式来计算,在云上测试是不会计算的
result=$[num1+num2]
echo ${result}
exit 0
输出结果
相等
200
字符串测试:
#!/bin/bash
str1="gav"
str2="vin"
if test $str1 = $str2;
then
echo '两个字符串相等'
else
echo '两个字符串不相等'
fi
exit 0
输出结果
两个字符串不相等
文件测试:
#!/bin/bash
# 脚本命令执行
# touch ./bash
# ./sh05.sh
# Shell还提供了与( -a )、或( -o )、
# 非( ! )三个逻辑操作符用于将测试条件连接起来
if test -e ./bash -a -e ./nofile;
then
echo '文件已经存在'
else
echo '文件不存在'
fi
exit 0
输出结果
文件不存在
流控制
IF-ELIF-ELSE:
#!/bin/bash
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
else
echo "a 小于 b"
fi
# 和test一起用也可以
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo "两个数字相等"
else
echo "两个数字不相等"
fi
exit 0
输出结果
a 小于 b
两个数字相等
FOR循环:
#!/bin/bash
# in列表可以包含替换、字符串和文件名
# 顺序输出列表中的数字
for loop in 1 2 3 4 5
do
echo "The value is : $loop"
done
# 输出数字的第2种形式
for((i=1;i<=5;i=i+1))
do
echo "The new value is : $i"
done
# 顺序输出字符串
k=1
for str in 'This is a String'
do
echo -e "$str 第$k次 \n"
k=$(($k + 1))
done
exit 0
输出结果
The value is : 1
The value is : 2
The value is : 3
The value is : 4
The value is : 5
This is a String 第1次
WHILE语句:
#!/bin/bash
inte=1
while [ $[inte] -lt 5 ]
# 另一种形式 while(( $inte <= 5))
do
echo ${inte}
let "inte++"
done
exit 0
输出结果
1
2
3
4
UNTIL循环:
#!/bin/bash
a=0
until [ ! $a -lt 5 ]
do
echo $a
a=`expr $a + 1`
done
输出结果
0
1
2
3
4
CASE:
#!/bin/bash
anum=1
case $anum in
1) echo "选择了1"
;;
2) echo "选择了2"
;;
*) echo "没了"
;;
esac
exit 0
输出结果
选择了1
跳出循环:
#!/bin/bash
echo -e "用break跳出\n"
for((i=1;$i<5;i++))
do
if [ $i == 2 ]
then
break
else
echo $i
fi
done
echo -e "用continue跳出\n"
for((i=1;$i<5;i++))
do
if [ $i == 2 ]
then
continue
else
echo $i
fi
done
exit 0
输出结果
用break跳出
1
用continue跳出
1
3
4
函数
函数:
处理函数参数
#!/bin/bash
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
exit 0
输出结果
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
输入输出重定向
输入输出重定向:
#!/bin/bash
# 标准输出重定向
who > "file1"
# 标准输出重定向追加
echo "who" >> "file1"
# 输入重定向
num=`wc -l < "file1"`
echo $num
# 标准输入文件(stdin):
# stdin的文件描述符为0,Unix程序默认从stdin读取数据。
# 标准输出文件(stdout):
# stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
# 标准错误文件(stderr):
# stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
# 计算行数
num=`wc -l << EOF
GAVIN
jou
大笨象
EOF
`
echo $num
# 屏蔽stdout 和 stderr
echo "hello" > /dev/nul 2>&1
exit 0
输出结果
1
3
文件包含
文件包含
# sh07.sh
#!/bin/bash
echo "HelloWorld\n"
#exit 0 千万别加这条语句,因为包含
# 有点像C的include复制粘贴效果,否则提早退出
# sh08.sh
#!/bin/bash
. ./sh07.sh # 或者用source ./sh07.sh
echo "HelloWorld2\n"
exit 0
输出结果
HelloWorld\n
HelloWorld2\n
『练习补充』
GITHUB