shell脚本
修改环境变量
1) 查看已有的特殊系统变量
系统配置好的,内置的环境
env 或者 printenv
2) 查看环境变量
echo $HOME
环境变量的作用:
当在终端直接运行指令时,会默认去环境变量保存的路径中查找指令,如果没找到该指令不能执行
3) 修改环境变量
i) 只对当前终端有效
新建环境变量: export HELLO="Hello!"
export PATH=${PATH}:/home/ubuntu
上面代码框中的效果:在当前终端给PATH添加了一个/home/ubuntu路径
ii) 只对当前用户生效
修改用户家目录下的 ~/.bashrc文件
由于是自己用户的家目录,所以不需要加sudo
vim ~/.bashrc
如没有以上内容,下面这个也是可以的
修改后重新打开一个终端即可生效
iii) 对所有的用户生效
修改 /etc/bash.bashrc 文件
sudo vim /etc/bash.bashrc
使用 export 表达式添加
iv) 对所有的用户生效
修改 /etc/environment 文件
sudo vim /etc/environment
只有一行PATH的信息,将想要添加的路径,以:为分隔加到原有路径后面即可
shell中的变量
shell变量没有数据类型的区别,shell是一种弱数据类型语言,shell中都当做字符串处理
1) shell中的格式
变量名=变量的值
变量名='变量的值' ---> 用于变量的值中间有空格
变量名="变量的值" ---> 用于使用已有变量的值和空格拼接给新变量赋值时(只要需要用已有变量的值都建议加"")
HELLO=hello
WORLD="$HELLO world"
=两侧不能有空格
''内不能使用$展开变量的值
2) 如何访问变量
$变量名 ---> 获取变量的值
${变量名} ---> 获取变量的值,为了更好区分变量名的范围
3) 修饰变量的关键字
readonly :只读变量,只不能更改
unset :清空变量的值,不能清空readonly修饰变量的值
local :定义局部变量,只能在函数中使用
4) 外部传参/位置变量
和C语言相同,脚本也可以在执行时进行外部传参,shell中通过位置变量获取参数
$0 ---> 执行的脚本名
$1-$9
$n ---> n >= 10,必须加上{}
${10}-${n}
$# ---> 获取所有外部参数的个数(不包括脚本名)
$* 或者 $@ ---> 获取所有的外部参数(不包含脚本名)
echo 输出内容(将内容回显到终端,并自动换行)
echo默认不解析转义字符
echo -n 输出内容 ------>取消echo输出时的换行
echo -e "hello\n" ------->解析转义字符
5) 输入
shell中read指令完成输入
read 变量名 ---> 直接加变量名即可
read -p "提示信息" 变量名 ---> 在终端给用户输入提示信息
read -s 变量名 ---> 输入的信息不回显
read -t 秒数 变量名 ---> 如果用户n秒不输入,就结束输入并向后执行语句
read -n 个数 变量名 ---> 如果输入n个字符,输入自动停止
#!/bin/bash
#read VAL1
#read -p "请输入三个数字,以空格隔开" A B C
# read -s A
# read -t 3 STR
read -n 5 STR
echo $STR
# echo $VAL1
# echo $A
# echo $B
# echo $C
6) 命令置换符
作用:获取该指令的执行结果
将一个命令的输出作为另一个命令的参数。
1. `指令` (反引号)
2. $(指令)
shell中的运算
shell本省不擅长运算,需要借助运算符和其他指令
(()) $[] let expr
1) (())
常用于shell中的整数算术运算
使用方法:
1.
(())几乎支持所有的C语言语法,还支持shell中幂运算**
2.
((表达式1, 表达式2, 表达式2, ...)) 每个表达式都会执行,获取最右侧一个表达式的结果
3.
想要获取运算结果,需要使用 $(()),还可以((变量名=表达式))
4.
在(())中,使用变量,可以加$,也可以不加
5.
在(())中,运算符两侧可以有空格
#!/bin/bash
read -p "请输入一个三位数" -n 3 num1
read -p "请输入一个三位数" -n 3 num2
echo $((num1+num2))
echo $((num1-num2))
echo $((num1*num2))
echo $((num1%num2))
2、比较root用户和当前用户uid的大小关系,输出较大的一个
#!/bin/bash
id_u=`id -u`
id_r=`id -u root`
echo $((id_u > id_r ? id_u : id_r))
2) $[]
使用方法:
1.
变量名=$[表达式1,表达式2,表达式3,·······]只获取最右侧表达式的结果
2.
使用变量时,可以加$也可以不加$
3.
运算符两侧可以加空格,也可以不加空格
4.
仍然支持幂运算
5.
$[]的结果,建议直接按照"变量名=$[]"格式接收,因为$[]本质上,会遗留一个运算结果在表达式的位置,如果不接受继续向后运行指令会报错
#!/bin/bash
num1=10
num2=20
echo $[num1+num2]
num3=$[num1 + num2]
echo $num3
3) expr
expr是一个终端指令
使用方法:
1.
expr 中使用变量,必须加$
2.
如果想要接收expr的结果,必须使用命令置换符
3.
expr中运算符两侧必须有空格,不支持自增、自减和shell中幂运算
4.
expr中使用某些运算符是,需要转义|、>、<、.、+、()、……(不需要记转义字符,简单的指令在运行前,去终端里运行一下指令)
5.
expr指令的结果,可以直接回显到终端上,可以使用命令置换符接收
6.
expr操作数值不能为空
expr进行算数运算
ARG1 | ARG2 若ARG1 的值不为0,返回ARG1,否则返回ARG2
ARG1 & ARG2 若两边的值都不为0,则返回ARG1,否则返回 0
ARG1 < ARG2 ARG1 小于ARG2
ARG1 <= ARG2 ARG1 小于或等于ARG2
ARG1 = ARG2 ARG1 等于ARG2
ARG1 != ARG2 ARG1 不等于ARG2
ARG1 >= ARG2 ARG1 大于或等于ARG2
ARG1 > ARG2 ARG1 大于ARG2
ARG1 + ARG2 计算 ARG1 与ARG2 相加之和
ARG1 - ARG2 计算 ARG1 与ARG2 相减之差
ARG1 * ARG2 计算 ARG1 与ARG2 相乘之积
ARG1 / ARG2 计算 ARG1 与ARG2 相除之商
ARG1 % ARG2 计算 ARG1 与ARG2 相除之余数
如果expr的操作数为空,会报语法错误
#!/bin/bash
expr $1 \> $2
2、计算/etc/passwd中,第20行uid和gid之和
#!/bin/bash
uid=`head -20 /etc/passwd|tail -1|cut -d : -f 3`
gid=`head -20 /etc/passwd|tail -1|cut -d : -f 4`
expr $uid + $gid
expr可以进行字符串的运算
match 字符串 表达式
返回表达式,在字符串中第一个位置起完全匹配成功的字符个数,如果能匹配成功,返回值就是表达式中字符的个数
substr 字符串 偏移量 长度
从字符串中偏移量的位置开始,截取指定长度的字符串,偏移量从1开始
index 字符串 字符
返回字符在字符串中第一次被查找到时得下标,下标从1开始
length 字符串
字符串的长度
str1="hello world"
str2="wor"
expr match "$str1" $str2 # str2不能在str1中的第一个位置开始完全匹配返回0
expr match "$str1" "hello" # 从第一位起匹配到的个数为5
expr substr "$str1" 1 3 # hel
expr substr "$str1" 7 5 # world
expr index "$str1" l # 3
expr index "$str1" le # 2 如果查找多个字符在字符串中的位置,返回最先出现的字符的位置
expr length "$str1"
4) let
使用方法:
1.
let运算时,运算符两侧一定不能有空格
2.
let 变量名=表达式 ---> let和变量名中一定要有空格
3.
let运算时,可以加$,也可以不加
4.
如果直接写成 let 表达式,表达式会运行,但是没有办法接收
#!/bin/bash
count_c=`ls ~/*c | wc -l`
count_sh=`ls ~/*sh | wc -l`
let count=count_c+count_sh
echo $count
6. shell中的数组
1) 定义
int arr[32];
int arr[] = {};
int arr[3] = {1, 2, 3};
shell中的数组
数组名=(val1 val2 val3 ...)
# shell中的数组,不需要写出数组长度
# shell中的数组初始化时,直接使用()
# shell中的数组每个元素之间是空格,不是逗号
# 访问仍然需要通过下标,下标从0开始
采用键值对的方式赋值
数组名=([下标值]=val1 [下标值]=val2 ...)
arr=([9]=1 [0]=4 ...)
下标可以不连续
采用列表名的方式赋值
列表名="val1 val2 val3 ..."
数组名=($列表名)
通过分别定义数组变量的方式赋值
数组名[0]="val1"
数组名[1]="val2"
2) 访问数组中的元素
只要在shell中需要使用变量的值,都需要用 $ 进行访问
${数组名[下标]} ---> 获取数组中指定下标的元素值
3) 获取数组中所有元素
${数组名[*]} ---> 获取数组中的所有元素
${数组名[@]} ---> 获取数组中的所有元素
获取数组中元素的个数
${#数组名[*]} ---> 获取数组中元素的个数
${#数组名[下标]} ---> 获取数组中指定下标元素的长度(字符个数)
对数组元素重新赋值
数组名[下标]=新值
#!/bin/bash
arr=(`ls ~`)
echo "家目录下文件的个数: ${#arr[*]}"
arr1=($*)
echo "所有的外部参数的个数: ${#arr[*]}"
4) 稀疏数组
下标不连续的数组
稀疏数组中元素的个数,由不为空的数据的个数决定
arr[0]=10
arr[3]=30
arr[8]=80
echo ${arr[*]}
echo ${#arr[*]} # 3
echo "添加数据前"
arr1=([2]=20 [4]=40 [0]=hello)
echo ${arr1[*]}
echo ${#arr1[*]} # 3
echo "添加数据后"
arr1[3]=world
echo ${arr1[*]}
echo ${#arr1[*]} # 4
5) 使用已有的数组给新的数组赋值
arr=(1 2 3 4 5)
arr1=(a b c d)
arr2=(${arr[*]} ${arr1[*]}) # 拼接加空格
echo ${arr2[*]}
echo ${#arr2[*]} # 9
拼接时两个数组中间没有加空格,第一个数组中的最后一个元素和第二个数组中的第一个元素会拼接在一起
拼接时两个数组中间加空格,两个数组独立起来拼接
6) 数组切片
取数组中的某一段的元素的值
格式:
${数组名[@ 或*]:起始位置(起始下标):长度}
#!/bin/bash# a. 在家目录下创建目录文件,dir
mkdir ~/dir# b. dir下创建dir1和dir2
mkdir ~/dir/dir1
mkdir ~/dir/dir2# c. 把当前目录下的所有文件拷贝到dir1中
cp * ~/dir/dir1# d. 把当前目录下的所有脚本文件拷贝到dir2中
find . -type f -name "*.sh" -exec cp {} ~/dir/dir2 \;# e. 把dir2打包并压缩为dir2.tar.xz
tar -cJf ~/dir/dir2.tar.xz -C ~/dir dir2# f. 再把dir2.tar.xz移动到dir1中
mv ~/dir/dir2.tar.xz ~/dir/dir1# g. 解压dir1中的压缩包
cd ~/dir/dir1
tar -xJf dir2.tar.xz
#!/bin/bash# a. 显示/etc/group文件中第五行的内容
sed -n '5p' /etc/group# b. 创建目录/home/ubuntu/copy
mkdir /home/ubuntu/copy# c. 切换工作路径到此目录
cd /home/ubuntu/copy# d. 复制/etc/shadow到此目录,并重命名为test
cp /etc/shadow ./ test# e. 将当前目录中test的所属用户改为root
sudo chown root test# f. 将test中其他用户的权限改为没有任何权限
chmod o-rwx test
#!/bin/bashurl="www.hqyj.com"# 使用 expr 和 sed 提取
protocol=$(expr "$url" : '\([^.]*\)')
domain=$(expr "$url" : '[^.]*\.\([^\.]*\)')
tld=$(expr "$url" : '[^.]*\.[^.]*\.\(.*\)')echo "$protocol"
echo "$domain"
echo "$tld"
read -p "请输入数组" -a arr
echo ${arr[*]}
echo ${#arr[*]}