文章目录
shell基础概念
Shell是一个命令解释器,它为用户提供一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以使用Shell来启动、挂起,停止、编写一些程序
shell是用户和内核中间的一个媒介
- 什么是shell编程?
shell编程就是组织shell语法写入一个文本
运行文件的是后依次执行命令,文件当中必须存在shell语法 - c语言和shell编程的比较
c语言 | shell编程 | |
---|---|---|
语法 | c语法 | shell语法 |
编译 | gcc编译器 | 不需要编译 |
文件后缀 | *.c | *.sh |
文件位置 | linux任何环境 | 一般写在家目录 |
执行 | ./hello | ./ hello.sh |
- C语言和shell运行方式
c语言: hello.c
1.编辑工程:VScode等编辑器生成hello.c
2.编译工程:gcc hello.c -o hello
,默认有权限执行权
3.测试工程:./ hello
shell编程: hello.sh
1.编辑工程:vi等编辑器 生成hello.sh文件
2.修改文件权限:chmod 777 hello.sh
3.测试工程:./hello.sh
- shell编程
1.shell编程没有头文件,没有主函数,里面所有命令都是bash解析器解析所以在执行所有的命令的时候,在文件的开头加上bash解析器的路径shel1因脚本的第一句必须是:# !/ bin/bash
# !/ bin/bash
的作用:指明解析器的路径
#!
是shell编程的特殊的标识符
当文件名为白色的时候,表示没有没有执行权限,改变执行权限之后可以执行
- 练习
练习: shell编程输出以下内容
cat dog pig
hello
welcome
echo -e "cat\tdog\tpig"
echo -e "hello\nwelcome"
-
echo (输内容到控制台)
-e:单行输出 -
脚本格式
- 脚本开头:
#!/bin/bash
shell中的变量和定义
3. Share脚本命名规则和C语言一样。
数字,字母,下划线,不能以数字开头。
-
变量不需要声明数据类型,所有的类型默认字符串类型。
-
shell语法给变量赋值的时候,等号的两边不能出现空格。
a=234,等号两边不能有空格。 -
变量的引用需要在变量之前加上$
a=hello
echo $a
就会输出a的值hello -
变量的种类
- 用户自定义变量
a=hello - 命令行变量
$#和$*
类似于C语言中的argc和argv
- 用户自定义变量
argc 是 argument count的缩写,表示传入main函数的参数个数;
argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称,并且包含了程序所在的完整路径,所以确切的说需要我们输入的main函数的参数个数应该是argc-1个;
. / num.sh 123 456 789
3 # $#返回值,返回参数个数,三个参数
123 456 789 # $*返回值,返回所有数值
123 # $1返回值,返回第一个数值
456 # $2返回值,返回第二个数值
789 # $3返回值,返回第三个数值
shell参数表示★
$#
命令行额外的参数(不包括执行脚本名即./名.sh)$*
命令行额外的内容(不包括执行脚本名即./名.sh)$1
命令行的第1个参数(argv[1])$2
命令行的第2个参数(argv[2])$?
代表最后一行的shell 语句的执行结果返回值
- 外部传参给内部变量
#!/bin/bash
a=$1 # a等于外部传参,a引用1
echo $a # 输出a的引用结果
cat $1
符号的作用
双引号
作用:将某些对象变成字符串输出
- 当字符串中有空格时必须使用双引号,如果没有可以不用加双引号。
str=hello
str="hello word "
- 当双引号中要对变量引用
echo "$a world"
- 在双引号当中调用shell命令,当shell命名需要识别的时候使用**反引号``**帮我命令。
echo " `ls -l` "
单引号
作用:将包裹的内容当作字符串使用
echo 'day is `date` ’ Date为命令加反引号
反引号
作用:识别双引号中的命令,并执行该命令。
重定向运算符 > >>
> 重定向到某一个文件完成覆盖
>> 重定向到某一个文件完成追加
例题:使用shell将Hello追加到2.TXT文件中,然后将ls -l内容也追加到2.TXT文件中
touch 2.txt // 创建2.TXT文件
echo "hello">2.txt
echo "`ls -l`">>2.txt
cat 2.txt // 输出2.TXT文件
字符串处理
计算字符串
str=jddojsafkjdfkjdfdlkfjkldjfkn
echo "${#str}" 计算长度为:
通配符
通配符 | 含义 |
---|---|
* | 代表任意长度的任意字符 |
? | 代表占一个长度的任意字符 |
[a-z] | 代表a到z当中一个长度的任意字符。 |
[az] | 代表a或z当中的一个长度的字符串。 |
[^az] | 代表指a和z以外的字符串(指定范围之外) |
% | 从右到左(←)尽可能少的匹配 |
%% | 从右到左(←)尽可能多的匹配 |
# | 从左到右(→)尽可能少的匹配 |
# # | 从左到右(→)尽可能多的匹配 |
- str=asgkdfhello,删除字符串str的左边的三个字符asg,其他的保留
从左到右进行一次查找
str=asgkdfhello
echo "${str#*asg}"
#:代表匹配方式
*:代表匹配内容
#:从左到右尽可能少
*:任意多
从左到右尽可能少删除任意多个字符到asg为止,包含asg
- 如果字符串str=asgkdfhello,删除前面的所有,只剩最后的hello
从左到右进行多次查找
str=asgkdfhello
echo "${str##*f}"
##: 从左到右尽可能多
* :任意多
从左到右尽可能多的删除任意多个字符,到f为止,包含f
删除总结:查找到删除的最近的字符,根据前后来删除
- 删除字符串str=asgkdfhello右侧的hello
从右到左,进行一次寻找
str=asgkdfhello
echo "${str%h*}"
%:右到左
*:任意多
从右到左,到h的位置截止,删除任意多分字符,包含h
- 删除字符串str=asgkdfhello右侧的字符,仅保留as
从右到左,进行多次匹配
str=asgkdfhello
echo "${str%%g*}"
%%:从右到左,进肯能多
*:任意多个字符
从右到左,进肯能多删除任意多个字符,到g为止,包含g
text语句
判断命令
语句 | 含义 | 说明 |
---|---|---|
文件判断 | ||
text -e file | 判断文件file是否 存在 | 是返回0,否返回1 |
text -r file | 判断文件file是否可读 | 是返回0,否返回1 |
text -w file | 判断文件file是否可写 | 是返回0,否返回1 |
text -x file | 判断文件file是否可执行 | 是返回0,否返回1 |
text -d file | 判断文件file是否是目录 | 是返回0,否返回1 |
text -f file | 判断文件file是否是普通文件 | 是返回0,否返回1 |
text -s file | 判断文件file是否非空 | 是返回0,否返回1 |
字符串判断 | ||
test s1 = s2 | 判断字符串s1和s2是否相同 | 相同返回0,否则返回1 |
test s1 != s2 | 判断字符串s1和s2是否不同 | 不同返回0,否则返回1 |
test s1 < s2 | 判断字符串s1是否小于s2 | s1小于s2返回0,否则返回1 |
test s1 > s2 | 判断字符串s1是否大于s2 | s1大于s2返回0,否则返回1 |
test -n s | 判断字符串s 长度是否为非0 | s长度为非0返回0,否则返回1 |
test -z s | 判断字符串s 长度是否为0 | s长度为0返回0,否则返回1 |
数组判断 | ||
test n1 -eq n2 | 判断数值n1是否等于n2 | n1等于n2返回0,否则返回1 |
test n1 -ne n2 | 判断数值n1是否不等于n2 | n1不等于n2返回0,否则返回1 |
test n1 -gt n2 | 判断数值n1是否大于n2 | n1大于n2返回0,否则返回1 |
test n1 -ge n2 | 判断数值n1是否大于等于n2 | n1大于等于n2返回0,否则返回1 |
test n1 -lt n2 | 判断数值n1是否小于n2 | n1小于n2返回0,否则返回1 |
test n1 -le n2 | 判断数值n1是否小于等于n2 | n1小于等于n2返回0,否则返回1 |
test测试语句
根据不同态势语句实现不同的操作。
- 判断命令行的执行参数是否为两个?如果不是两个就报错。
test $# -ne 2 条件
if(条件)
echo "error"
else
echo ""
分支控制语句
C语言:
分支: if-else switch-case
控制: while do-while for goto
shell和C语言的分支控制相同
分支:if-else-fi case-esac
控制:while for until
1. if-else-fi 两种情况的判断
if 判断条件(test测试语句)
then
xxxx
else
xxxx
fi
-
fi:是结束if语句的标志
$#
命令行额外的参数(不包括执行脚本名即./名.sh)
$*
命令行额外的内容(不包括执行脚本名即./名.sh)
$1
命令行的第1个参数(argv[1])
$2
命令行的第2个参数(argv[2])
$?
代表最后一行的shell 语句的执行结果返回值 -
练习:判断参数是否大于2
if test $# -ne 2
then
echo "error"
else
echo "good"
fi
去掉test的等价命令
if[ $# -eq 2 ] // 注意在[]里面的内容要与[]都保持有一个空格
then
echo "error"
else
echo "good"
fi
2. 三种情况的判断
三种情况框架:
if 判断条件 // if后面都要跟一个then(一个if配一个then)
then
XXXXX
elif 判断条件
then
XxXXX
else
XXXX
fi
注意:
- 每一个if语句都要有fi作为结尾(fi是if语句的标志)
- if判断条件为真,才能执行Lhen后面的语句(一个if配一个then)
- if 判断条件等价于if判断条件;,后面有没有;都可以
例子:使用命令行传参,传递两个参数if-elif-else-fi
如果numl>num2 , num1>num2
如果numl=num2 , numl=num2
如果numl<num2 , numl<num2
if test $1 < $2
then
echo "$1 < $2"
elif test $1 >$2
then
echo "S1 > $2"
else
echo "$1 = $2"
fi
3. 分支:case
C语言:
switch格式:
switch(变量)
{
case l: xSxXx;
break;
case 2: xSXxx ;
break;
case 3: ×SXXx ;
break ;
default: xXxx;
break;
}
shell:框架
case 变量 in
xx)
aaaa;; //变量如果是xx,那么执行该语句
// 没有break就加两个;,第二个;就相当于break
yy)
bbbb ; ;
zz)
XXX××;;
*) //其他情况
XXXx;;
esca // 结束标志
case $1 in
12)
echo "12";;
13)
echo "13";;
*)
echo "456";;
esac
键盘输入
c语言:scanf ( "sd" , &a ) ;
shell:
输入: read
read str // 获取键盘输入一个字符串保存到变量
read -p "please input a num" s // -p 参数 打印“”中提示语句并输入一个内容,为s
运算
运算符:+ - * / %
shell:
格式:`expr 变量1 运算符 变量2 开头有一个反双引号
echo "please input a nun"
read str
echo $str
read -p "please input a nun " s
echo $s
sums=`expr Sstr + $secho $sursl
练习:
1.利用shell脚本实现,c语言的模板
./ c.sh 1.c
#include <stdio.h>
int main (int argc, char **argv)
{
return 0;)
}
建立一个 .sh文件,在.sh文件里面输入一下代码
这里代码放在了home1.sh文件里
#!/bin/bash
// 往文件里面写,没有文件写不了
// 先判断传进来的参数,
if test $# -ne 1
then
echo "error"
fi
// 外部传参第一个,自定义一个文件名为filename,然后输入定义这个文件名
filename=$1
// 然后输出要输出的东西,并追加到指定的文件里面
echo "#include <stdio.h>">$filename
echo " ">>$filename
echo "int main (int argc, char * *argv) ">>$filename
echo " { ">>$filename
echo " } ">>$filename
// 直接打开文件名
gedit $filename
改变一下home1.是文件的权限:chmod 777 home1.sh
然后执行
- 利用case和expr read计算,实现计算器的加减乘除
创建一个.sh文件,并在文件里面输入一下代码
#!/bin/bash
echo "input nup1"
read str1
echo "input type" // 运算符
read c
echo "input num2"
read str2
case $c in
+)
echo " $str1 + $str2 ='`expr $str1 + $str2`" ; ;
-)
echo "$str1 - $str2 = '`expr $str1 - $str2`"; ;
\*)
echo "$str1 * $str2 = '`expr $str1 \* $str2`" ; ;
/)
echo $str1 / $str2 ='`expr $str1 / $str2`" ; ;
esac
- 写一个脚本实现如下功能
1.显示当前的系统时问,然后创建一个目录/ tmp/lstest
2.切换工作路径/ tmp / lstest
3.创建目录ald b56a otest.4.创建文件 xyx2y 732
5.列出当前目录下以a,x或者6开头的文件或者日录
创建一个.sh文件,并在文件里面输入一下代码
echo 'date'
sudo mkdir /tmp/lstest
cd /tmp/lstest
sudo mkdir ald b56a 6test
sudo touch xyx2y 732
ls [ ax6]*
ls | grep ^a
ls | grep ^x
ls | grep ^6
sudo 是一种权限管理机制,管理员可以授权于一些普通用户去执行一些 root 执行的操作,而不需要知道 root 的密码。
for循环
c语言:
for(循环变量初始化;判断循环条件;条件累计)
{
循环体 ;
}
shell框架:
for 循环变量 in 次数
do // 循环体放在do和done之间
循环体
done
区间次数表示: `seq 1 5` 次数1到5次
练习1:输出五次
文件为for.sh
seq 1 5:表示产生1到5之间的所有数
#!/bin/bash
for i in 'seq 1 5`
do
echo "i is si: hello world"
done
c语言:
int i 整型
shell:
存放整型数据declare -i n=整数
!/bin/bash
declare -i n=1
n=$n+1
echo $n
练习2:尝试for 将命令行的参数全部打印出来
#!/ bin/ bash
declare -i n=1
for data in $*
do
echo "argv [$n] : $data"n=$n+1
done
练习3: shell编程实现从1+2+3+…+100
#!/bin/bash
for i in `seq 1 100`
do
sum= ``expr $sum + $i`
done
echo $sum
while循环
c语言:
while(判断条件) 条件为真执行条件为假不执行
{
循环体
}
shell:
while 判断条件(test测试语句[])
do
循环体
done
- 循环体放在do和done之间
练习1:在终端上打印1到100的值
#!/ bin/bash
declare -i n=1
while test $n -le 100
do
echo " $n"
n=$n+1
done
练习2:使用shell,while循环实现10 !
#!/bin / bash
declare -i n=1
declare -i s=1
while test $n -le 10
do
s=$s \ * $n
n=$n+1
done
echo $s
函数
shell编程中的函数和C语言的函数非常相似,功能内容封装
框架:
函数名()
{
函数封装内容
}
注意:
- shell函数里面不需要写形参和返回值,默认类型是int类型
- 在函数内部,
$#
和$*
代表函数的内部的 参数和个数(不是命令的参数和参数个数) - 函数内部的参数要和传参一致,否则传不进去
- 再调用的时候参数传递,不需要添加括号
fun (hello,world) ; //错误的
fun hello world //正确的
信号的捕捉
正则表达式
四、正则表达式
正则表达式RE,实际上特殊符号的组成的一个式子,帮助你模糊查询
grep 寻找对象
- 语法:
grep 寻找范围 寻找对象参数
参数 | 作用 |
---|---|
-H | 将你查询的文件名输出 |
-n | 打印匹配的行号 |
-w | 全字匹配,只有一模一样的才会输出 |
grep 配套的
练习:查找以hello为开头的
grep '^hello' 3.txt -Hn
练习:查找以hello为结尾的
$放在结尾
grep 'hello$' 3.txt -Hn
例子.查询电话簿
区号是3位或者4位
并且是0开头的
电话号码和区号之前要么是空格要么是-
所有的区号和电话号码都只能数字8位到9位
区号是3位或者4位:[0,9]\{3,4\},\是转义字符
并且是0开头的:^0
电话号码和区号之前要么是空格要么是-:[ -]
所有的区号和电话号码都只能数字8位到9位[0-9]\{8,9\}
grep '^0[0-9]\{3,4\}[ -][0,9]\{8,9\}' phone.txt -Hn
练习:
作业:
1 .shell脚本
使用shell脚本生成一个随机数,提示猜测数字,每次输入都会提示猜大了或者猜小了,直到用户猜对了就退出
$RANDOM
# !/ bin/ bash
declare -i num
declare -i a
num=$( ($RANDOM%100+0))
read -p "input num: " a
while test $num -ne $a
do
if test $num -gt $a
then
echo "num > a"
elif test $num -lt $a
then
echo "num < a"
fi
read -p "input num=" a
done
2.使用ls遍历当前目录下的文件,如果文件存在并可读就打印文件名,如果存在不可读就打印error
#!/ bin/ bash
for str in `ls`
do
if test -e $str & & test -x $str
then
echo $str
elif test -e $str
then
echo "error"
fi
done
附加题:
3.读取普通文件,提示用户和密码输入
如果输入的内容和文件中的内容一致,打印登录成功,否则登录失败