目录
1. shell基本知识
shell(计算机外壳),它是命令解释器,在操作系统的最外层,把用户的输入解释给操作系统。
如果有一系列经常需要使用的命令,把它存储在一个文件里,shell可以读取这个文件并顺序执行其中的命令,我们把这样的文件就叫shell脚本。shell脚本按行解释文件里的命令。
shell脚本的基本元素
对于一个基本的Shell程序来说,应该拥有以下基本元素:
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
[root@localhost ~]# echo $SHELL
/bin/bash
- 声明:声明用哪个命令解释器来解释并执行当前脚本文件中的语句,一般写的解释器为
#!/bin/bash
- 命令:可执行语句,实现程序的功能。
- 注释:说明某些代码的功能,通过在代码中增加注释可以提高程序的可读性。
(1)单行注释:#开头的一整行都是注释,例如:
#comment1
#comment2
#comment3
……
(2)多行注释,使用冒号“:”配合here document可实现多行注释,例如:
:<<BLOCK
……注释内容
BLOCK
- 赋予rx的权限
2.命令使用
echo
作用:可在屏幕上输出信息
echo参数选项 | 说明 |
---|---|
-n | 不换行输出 |
-e | 解析转义字符 |
转义字符 | 说明 |
---|---|
\n | 换行 |
\r | 回车 |
\t | 制表符 |
\b | 退格 |
\v | 纵向制表符 |
示例:
#不加任何参数时的输出
[jzl@localhost ~]$ echo i am a student
i am a student
[jzl@localhost ~]$
# 加上-n参数后
[jzl@localhost ~]$ echo -n i am a student
i am a student[jzl@localhost ~]$
#加入转义字符\t后,不写入参数
[jzl@localhost ~]$ echo i\tam\ta\tstudent\t
itamtatstudentt
#直接加上参数-e
[jzl@localhost ~]$ echo -e i\tam\ta\tstudent\t
itamtatstudentt
#将后面输入的用双引号
[jzl@localhost ~]$ echo -e "i\tam\ta\tstudent\t"
i am a student
#使用转义字符\n
[jzl@localhost ~]$ echo -e "i am a student\n"
i am a student
[jzl@localhost ~]$
eval
功能:当shell程序执行到eval语句时,shell读入参数args,并将它们组合成一个新的命令,然后执行。
命令格式:eval args
示例:
[jzl@localhost ~]$ a='shuju;head -2 /etc/passwd'
[jzl@localhost ~]$ echo $a
shuju;head -2 /etc/passwd
[jzl@localhost ~]$ eval echo $a
shuju
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
#试一下管道,发现eval不适合标准输入
[jzl@localhost ~]$ echo $a|eval
[jzl@localhost ~]$
#依次试一试发现一下eval是如何执行的
[jzl@localhost ~]$ eval echo 'shuju'
shuju
[jzl@localhost ~]$ eval echo 'head -2 /etc/passwd'
head -2 /etc/passwd
[jzl@localhost ~]$ head -2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[jzl@localhost ~]$ eval echo "shuju;head -2 /etc/passwd"
shuju
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[jzl@localhost ~]$ eval echo "shuju";head -2 /etc/passwd
shuju
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
exec
作用:能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该进程就终止了。
示例:
[jzl@localhost ~]$ cd /etc/
[jzl@localhost etc]$ exec cd /home
Connection to 192.168.10.128 closed.
read
作用:可从标准输入读取字符串等信息,传给shell程序内部定义的变量
read参数选项 | 说明 |
---|---|
-p | prompt:设置提示信息 |
-t | timeout :设置等待时间,单位默认为秒 |
示例:
#读取字符串,其提示为请输入姓名:,等待时间为5s,执行后不输入姓名等待5s,会自动结束
[root@localhost ~]# read -p "please input name:" -t 5 name1
please input name:[root@localhost ~]#
[root@localhost ~]# read -p "please input name:" name1 name2
please input name:Tom Johy
[root@localhost ~]# echo $name1
Tom
[root@localhost ~]# echo $name2
Johy
#使用read从标准输入读取两个变量: name1和name2, 要求name1包含空格
[root@localhost ~]# read -p "please input name:" name1 name2
please input name:James\ Webb Tom
[root@localhost ~]# echo $name1
James Webb
[root@localhost ~]# echo $name2
Tom
[root@localhost ~]#
shift
作用:shift,在程序中每使用一次shift语句,都会使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止。
$# $* $@ $n $?的使用
变量 | 说明 |
---|---|
$# | 命令行参数的个数 |
$n | 表示传递给脚本的第n个参数,例如$1表示第一个参数,$2表示第二个参数,$3表示第三个参数 |
$0 | 当前脚本的名称 |
$* | 以"参数1 参数2 参数3…"的形式返回所有参数的值 |
$@ | 以“参数1”“参数2”“参数3”…的形式返回所有的值 |
$? | 前一个命令或者函数的返回状态码。" $ ?" 的返回值用法:(1)判断命令、脚本或函数等程序是否执行成功(2)若在脚本中调用执行“exit 数字”,则会返回这个数字给 “$ ?” 变量(3)如果是在函数里,则通过“return 数字”把这个数字以函数值的形式传给“$?” |
$$ | 返回本程序的进程ID(PID),不常用 |
$! | 获取上一个在后台工作的进程的进程号,不常用 |
$_ | 保存之前执行的命令的最后一个参数,不常用 |
示例: |
[root@localhost day1]# vim shift_test.sh
# 命令行参数的个数
echo "count1: $#"
# 第1个位置参数
echo "data1: $1"
# 第2个位置参数
echo "data2: $2"
# 当前脚本的名称
echo "name: $0"
# 所有参数
echo "all_data1: $*"
echo "all_data2: $@"
# 当前进程的PID
echo "PID: $$"
shift
#shift过后再次查看命令行参数的个数
echo "count2: $#"
[root@localhost day1]# bash shift_test.sh 1234 5678
count1: 2
data1: 1234
data2: 5678
name: shift_test.sh
all_data1: 1234 5678
all_data2: 1234 5678
PID: 9459
count2: 1
&*与&@的区别
会发现&和&@表面显示是一样,不同的在哪呢?
$:以"参数1 参数2 参数3…"的形式返回所有参数的值
例:“1234 5678”
$@:以“参数1”“参数2”“参数3”…的形式返回所有的值
示例1: “1234”“5678”
[root@localhost day1]# set -- "i have" a cat
[root@localhost day1]# echo $#
3
[root@localhost day1]# echo $*
i have a cat
[root@localhost day1]# echo $@
i have a cat
[root@localhost day1]# for i in $*;do echo $i;done
i
have
a
cat
[root@localhost day1]# for i in $@;do echo $i; done
i
have
a
cat
[root@localhost day1]# for i in "$*";do echo $i;done
i have a cat
[root@localhost day1]# for i in "$@";do echo $i;done
i have
a
cat
示例2:
[root@localhost day1]# cat shift_test2.sh
for i in "$*"
do
echo $i
done
echo "--------------"
for i in "$@"
do
echo $i
done
echo "--------------"
[root@localhost day1]# bash shift_test2.sh 1234 5678
1234 5678
--------------
1234
5678
--------------
[root@localhost day1]#
exit(要求退出码为222)
作用:退出shell程序。在exit之后可以有选择地指定一个数作为返回状态
[root@localhost day1]# vim exit_test.sh
echo "123"
exit 222
echo "456"
[root@localhost day1]# bash exit_test.sh
123
[root@localhost day1]# echo $? #查看退出码
222
如何快速如何快速生成脚本开头的版本版权注释信息
[root@localhost ~]# vim ~/.vimrc
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1,"#!/bin/bash")
call setline(2,"#########################")
call setline(3,"#File name:".expand("%"))
call setline(4,"#Version:v1.0")
call setline(5,"#Email:admin@test.com")
call setline(6,"#Created time:".strftime("%F %T"))
call setline(7,"#Description:")
call setline(8,"#########################")
call setline(9,"")
endif
endfunc
# 然后再创建.sh的文件,发现会自动生成注释信息
[root@localhost ~]# vim haha.sh
#!/bin/bash
#########################
#File name:haha.sh
#Version:v1.0
#Email:admin@test.com
#Created time:2022-08-15 19:36:51
#Description:
#########################
3.定义自定义环境变量
export
作用:设置或显示环境变量
示例:
#显示所有环境变量
[root@localhost day1]# export
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/0/bus"
declare -x DISPLAY="localhost:10.0"
.......
declare -x which_declare="declare -f"
#设置环境变量
[root@localhost day1]# a=1234
[root@localhost day1]# export a #设置a为环境变量
[root@localhost day1]# echo $a
1234
[root@localhost day1]# unset a
[root@localhost day1]# echo $a
[root@localhost day1]#
declare
作用:使用declare声明变量类型:既然所有变量的默认类型是字符串型,那么只要我们把变 量声明为整数型就可以进行运算了。使用declare命令就可以实现声明变量的类型。
declare [+/-][选项] 变量名
变量 | 说明 |
---|---|
选项 | 说明 |
- | 给变量舍得类型属性 |
+ | 取消变量的类型属性 |
-a | 将变量声明为数组型 |
-i | 将变量声明为整型 |
-x | 将变量声明为环境变量 |
-r | 将变量声明为只读变量 |
-p | 查看变量的被声明的类型 |
针对root用户的所有连接 | root_data=root |
针对所有用户的变量 | all_data=all |
查看所有的环境变量 | 查看所有变量 |
示例:
#设置环境变量
[root@localhost day1]# declare -x test=1234 #用declare命令-x选项将test=123声明为环境变量。
[root@localhost day1]# env | grep test # #在env中查找是否有test的环境变量
OLDPWD=/root/test
test=1234
PWD=/root/test/day1
#查看所有环境变量
[root@localhost day1]# declare
......
#查看所有环境变量
[root@localhost day1]# env
......
示例:
针对root用户的所有连接:root_data=root
针对所有用户的变量: all_data=all
[root@localhost day1]# root_data=root
[root@localhost day1]# export root_data
[root@localhost day1]# all_data=all
[root@localhost day1]# declare -x all_data
[root@localhost day1]# env | grep data
all_data=all
root_data=root
[root@localhost day1]#
#查看所有环境变量
[root@localhost day1]# declare
......
#查看所有环境变量
[root@localhost day1]# env
......
#显示所有环境变量
[root@localhost day1]# export
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/0/bus"
declare -x DISPLAY="localhost:10.0"
.......
declare -x which_declare="declare -f"
4.脚本执行的方式及特点
1)交互式
[root@localhost day1]# for filename in `ls /etc`
> do
> if echo "$filename" | grep "passwd"
> then
> echo "$filename"
> fi
> done
passwd
passwd
passwd-
passwd-
[root@localhost ~]#
(2)作为程序文件执行(常用)
[root@localhost day1]# vim method2.sh
#!/bin/bash
for filename in `ls /etc`
do
if echo "$filename" | grep "passwd"
then
echo "$filename"
fi
done
[root@localhost day1]# bash method2.sh
passwd
passwd
passwd-
passwd-
5.执行脚本的方法
(1)bash ./filename.sh(产生子进程,再运行,使用当前指定的bash shell去运行)
[root@localhost day1]# bash method.sh
hello
(2)./filename.sh(产生子进程,再运行,使用脚本里面指定的shell去运行。使用该种方式执行需要x权限)
[root@localhost day1]# ./method.sh
-bash: ./method.sh: Permission denied
[root@localhost day1]# chmod a+rx method.sh
[root@localhost day1]# ./method.sh
hello
(3)source ./filename.sh(source命令是一个shell内部命令,其功能是读取指定的shell程序文件,并且依次执行其中的所有的语句,并没有创建新的子shell进程,所以脚本里面所有创建的变量都会保存到当前的shell里面)
[root@localhost day1]# source ./method.sh
hello
(4). filename.sh(和source一样,也是使用当前进程执行)
[root@localhost day1]# . method.sh
hello
6.设置vim编辑sh文件的缩进为4个空格
#方法1:
[root@localhost ~]# vim ~/.vimrc
set tabstop=4 #在文件后添加
#方法2:(推荐)
[root@localhost ~]# vim ~/.vimrc
autocmd FileType sh setlocal ai ts=4 sw=4 et #可以进行文件类型的修改,也可以自定义缩进的空格
#验证
创建一个sh文件,测试一下tab键
7.shell中的引用(引号的作用)
在bash中有很多特殊字符,这些特殊字符就具有特殊含义。引用就是通知shell将这些特殊字符当作普通
字符来处理。
符号 | 说明 |
---|---|
转义字符“\” | 如果将\放到特殊字符前面,shell就忽略这些特殊字符的原有含义,把它们当作普通字符对待 |
单引号 | 如果将字符串放到一对单引号之间,那么字符串中所有字符的特殊含义被忽略 |
双引号 | 双引号的引用与单引号基本相同,包含在双引号内的大部分特殊字符可以当作普通字符处理,但是仍然有一些特殊字符保留自己的特殊含义,比如”$“和“\”以及“ ` ” |
.反向引号( ) | 在执行时,shell 首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分。 注:命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置。位于键盘Tab键上面一行的键,用作命令替换(相当于$(…)) |
[root@localhost ~]# echo $USER
root
[root@localhost ~]# echo "user is $USER" #双引号
user is root
[root@localhost ~]# echo 'user is $USER' #单引号
user is $USER
[root@localhost ~]# echo `echo user is $USER` #反引号
user is root
[root@localhost ~]# echo ` user is $USER`
bash: user: command not found...
[root@localhost ~]# echo "user is '$USER' "
user is 'root'
[root@localhost ~]# echo 'user is "$USER"'
user is "$USER"