「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
1、shell基础
命令与逻辑语言共存,类似于C语言
&& ||具有逻辑判断, &&是前一个命令失败,后面不会执行,||是前一个命令失败,后面命令若能执行则执行。
;不影响命令执行
`mkdir /home/1/2/3 &&echo "OK"`#两条命令都不会执行
`mkdir -p /home/1/2/3 &&echo "OK"`#会显示ok,因为-p表示如果没有目录会自动创建,-p表示递归创建
输出命令
echo 内容
echo 输出颜色文本
echo -e "\e[1;31m this is text.\e[0m"
31-37文字颜色,41-47文字背景颜色
echo -e "\e[1;31m \e[1;42m this is text.\e[0m"
可以连用,不加尾部\e[0m表示以后输出一直为此颜色
命令后跟&
& 的作用就是将这个任务放到后台执行
command &>/dev/null
混合重定向到无底洞
通配符
- *表示匹配任意多个字符 如:
ls aa * rm -rf *;
- ?表示匹配任意单个字符
touch love loove live l7ve;ll l?ve
- []匹配括号中的任意一个字符
[abc]
,[^a-Z]
^表示取反,正则表达式内容,除括号以外的内容 - ()在子shell中执行
(cd /boot;ls)(umask 077;touch file1000)
- {}集合touch file{1…9}创建文件file1-file9,
mkdir /home/{111,222},mkdir -pv /home/{333/{aaa,bbb},444}
2、变量
shell变量使用一个特定的字符串表示不固定的内容,
$variable
引用变量的值
#!/bin/bash
ip=127.0.0.1 #本地还回
ping -c1 $ip &>/dev/null && echo "$ip is up " ||echo "$ip is down";
自定义变量
-
定义变量: 变量名=变量值 变量名必须是以字母或下划线开头,区分大小写。如:
ip=127.0.0.1
-
引用变量: $变量名 或${变量名}
-
查看变量: echo $变量名 set(所有变量:包括自定义变量和环境变量)
-
取消变量: unset变量名
-
作用范围: 仅在当前shell有效
#!/bin/bash
ip=127.0.0.1 #本地还回#变量和等号和值之间不能有空格#显示赋值
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then#注意空格 ,否则出错
echo "ip is up"
else
echo "ip is down"
fi
环境变量
-
定义环境变量:
- 方法一 :
export back_dir2=/home/backup
- 方法二:
export back_dir1
将自定义变量转换成环境变量
- 方法一 :
-
引用环境变量: $变量名或者${变量名}
-
查看环境变量:echo $变量名, env , 例如env |grep back_dir2
- env显示所有环境变量
-
取消环境变量:unset变量名
-
变量作用范围:在当前shell和子shell有效
-
一个脚本用另个脚本里变量:
- 方法一:另一个脚本变量设为全局变量
- 方法二:在一个脚本里加载另一个脚本
#!/bin/bash
. 1.sh #v1在1.sh里#当前shell 执行#.和source都表示当前shell运行
echo -e "$v1"
位置变量
1.sh 1 2 3 4 5 6#$1 $2 $3 $4 ${5} 分别表示1 2 3 4 5
预定义变量
表达式 | 含义 |
---|---|
$0 | 脚本名 |
$* | 所有的参数,参数指脚本运行时后面的参数 |
$@ | 所有的参数 |
$# | 参数的个数 |
$$ | 当前进程的PID |
$! | 上一个后台进程的PID |
$? | 上一个命令的的返回值 0表示成功 |
#!/bin/bash
#如果脚本没有参数
if [ $# -eq 0 ]; then
echo -e "usage: `basename $0` file" #反引号,执行引号里面命令
exit
fi
if [ ! -f $1 ]; then#判断$1是不是常规文件,!取反
echo "error file"
exit
fi
for ip in `cat $1`
do
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then #if后面有空格
echo "$ip is up"
else
echo "$ip is down"
fi
done
反引号,执行引号里面命令 basename 基本文件名 dirname 基本目录名
显示赋值
变量名=变量值
ip=127.0.0.1
school=“HDU_University”
today1=`date +%F`
today2=$(date +%F)
read从键盘读入变量值
-
read 变量名
-
read -p “提示信息:” 变量名
-
read -t 5 -p “提示信息:” 变量名 //等待5s时间
-
read -n k 变量名 //需要k个字符
"",``与‘’的区别
-
""弱引用
-
''强引用
示例:
name="mary" ;boy1="name is good'含义为boy1=mary is good,boy2=$name is good;
touch `date +%F`_file_txt ``表示执行``里面的命令在执行外面的
变量运算
变量运算方法1——expr
-
expr 1+2
-
expr $v1+$v2
-
expr $v1*$v2
变量运算方法2——$(())
-
echo v1+$v2))
-
echo $((v1+v2))
-
echo $((5-3))
-
echo $(((5-3)*2))
-
echo $((5**3)) //5的立方,n**k n的k方
-
sum=$((1+2))
变量运算方法3——$[]
和方法二一样
变量运算方法四let
-
let sum=2+3;
-
let i++
#!/bin/bash
ip=1.0.0.127
i=1
while [ $i -le 5 ] #-le 表示小于#记住[] 两头都要用 隔开
do
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo "$ip is up"
fi
let i++
done
整数运算
-
echo “2*4” |bc
-
echo “2^4” |bc
-
echo “scale=n;6/4” |bc //小数点后n位
bc表示计算
变量内容的删除和替换
删除变量的部分(本身不变)
前删
name=www.baidu.com
-
echo ${name#*.} 删除www.
-
echo ${name##*.}删除www.baidu.//贪婪匹配删除到最后一个.之前
后删
-
echo ${name%.*}删除.com
-
echo ${name%%.*}删除.baidu.com//贪婪匹配删除到最后一个.之前
切片
-
echo ${name:0:5}//取位置0开始后面5位
-
echo ${name:5:5}//取位置5开始后面5位
-
echo ${name:5}//取位置5后面所有
替换
-
echo ${name/baidu/sina}//把baidu替换为sina
-
echo ${name/b/B}//修改第一个字符b为B
-
echo ${name//w/W}//把所有w变成W
3.条件测试
test -d $v1 判断v1是不是目录 ,bash -vx .sh以调试的方式执行,test与[ ]一样
以下都可以通过命令man test查看
-
test条件表达式
-
[ 条件表达式 ], [ A 条件 B ]不能忽略空格,C风格可以
-
[[ 条件表达式 ]]
文件测试
格式 | 含义 |
---|---|
-r file | 当前用户是否有读权限 |
-L file | 文件是否是连接文件 |
-b file | 文件是否为设备文件 |
-c file | 文件是否为字符设备文件 |
-d file | 文件存在并且是一个目录 |
-e file | 文件已存在 |
-f file | 文件存在并且是常规文件 |
-g file | 文件已存在并设置为组ID |
-G file | 文件存在并且由有效组ID拥有 |
-h file | 文件存在并且是符号链接(与-L相同) |
-k file | 文件存在并设置了其粘滞位 |
-L file | 文件存在并且是符号链接(与-h相同) |
-O file | 文件存在并且由有效用户ID拥有 |
-p file | 文件存在并且是命名管道 |
-r file | 文件已存在并已授予读取权限 |
-s file | 文件存在且大小大于零 |
-S file | 文件存在并且是套接字 |
-u file | 文件存在并且其设置用户ID位已设置 |
-w file | 文件已存在并授予写入权限 |
-x file | 文件存在并授予执行(或搜索)权限 |
数值测试
INTEGER1 -eq INTEGER2 #等于
INTEGER1 is equal to INTEGER2
INTEGER1 -ge INTEGER2#大于等于
INTEGER1 is greater than or equal to INTEGER2
INTEGER1 -gt INTEGER2#大于
INTEGER1 is greater than INTEGER2
INTEGER1 -le INTEGER2#小于等于
INTEGER1 is less than or equal to INTEGER2
INTEGER1 -lt INTEGER2#小于
INTEGER1 is less than INTEGER2
INTEGER1 -ne INTEGER2#不等于
INTEGER1 is not equal to INTEGER2
C风格的数值判断
((C条件判断))
#!/bin/bash
#如果脚本没有参数
if [ $# -eq 0 ]; then
echo -e "usage: `basename $0` file" #反引号,执行引号里面命令
exit
fi
if [ ! -f $1 ]; then
echo "error file"
exit
fi
for ip in `cat $1`
do
ping -c1 $ip &>/dev/null
if (($?==0));then #if后面有空格
echo "$ip is up"
else
echo "$ip is down"
fi
done
字符串比较
-n STRING#字符串非空
the length of STRING is nonzero
STRING equivalent to -n STRING
-z STRING#字符串为空
the length of STRING is zero
STRING1 = STRING2#相等
the strings are equal
STRING1 != STRING2#不相等
the strings are not equal
表达式
( EXPRESSION )
EXPRESSION is true
! EXPRESSION
EXPRESSION is false
EXPRESSION1 -a EXPRESSION2
both EXPRESSION1 and EXPRESSION2 are true
EXPRESSION1 -o EXPRESSION2
either EXPRESSION1 or EXPRESSION2 is true
用户创建
#!/bin/bash
read -p "Please input the number of users: " number
if [[ ! "$number" =~^[0-9]+$ ]];then
echo "$number is not number."
fi
read -p "Please input a name for users: " string
for i in `seq $number`
do
user=$string$number
useradd $user
if [ $? -eq 0 ];then
echo "$user is created."
fi
done
4、流控、循环
if
if 条件测试
then
内容
elif 条件测试
then
内容
elif 条件测试
then
内容
else #注意此处没有then 加then是错误语法
内容
fi
case
case 变量 in
模式一)#加不加引号一样,匹配空字符时要加""
命令序列
;;#分号一定不能少
模式二)
命令序列
;;
模式三)
命令序列
;;
*)
无匹配的默认序列
esac
示例:删除用户
#!/bin/bash
#del user
#by dengwei
#date 2021.4.21
read -p "Please input a user: " user
id $user&>/dev/null
if [ $? -ne 0 ]; then
echo "username is not exist"
exit -1
fi
read -p "Are sure?[y]" action
case "$action" in
y|Y|yes|YES)
userdel -r $user
echo "success"
;;
"*")
echo "exit"
esac
简单测试
#!/bin/bash
#del user
#by dengwei
#date 2021.4.21
read -p "Please input a user: " user
read -p "Are sure?[y]" action
case "$action" in
y|Y|yes|YES)
echo "success"
;;
"*")
echo "exit"
esac
for(对文件逐行处理最好用while)
for 变量 in {取值列表}
do
命令序列
done
for 变量 #后面什么都不加表示获取所有参数
do
命令序列
done
示例:
#!/bin/bash
ip=www.baidu.com
for i in {1..100}
do
{//将循环放在后台加快速度{}&
ping -c1 $ip&>/dev/null
if [ $? -eq 0 ]; then
echo "$ip"
fi
}&
done
wait#等待前面所有后台结束
echo "finish"
{
}&#将循环放在后台加快速度{}&
IFS=“\n”按行分割 IFS修改分隔符
#!/bin/bash
IFS="\n"
if [ $# -eq 0 ];then
echo "please input a file"
exit -1
fi
if [ ! -f $1 ];then
echo "$1 isn't a file"
exit -1
fi
for i in `cat $1`
do
echo "$i"
done
while
while 条件测试
do
循环体
done#<file/$1等会输入重定向
条件测试为真时执行
until
until 条件测试
do
循环体
done
条件测试为假时执行
break(同C语言)
continue(同C语言)
exit(同C语言)
shift
将位置变量往左移动, shift n往左移动n个,并减少参数总共个数
./1.sh 1 2 3
脚本内部shift 1 一次,参数变为 2 3分别对应$1 $2
5、数组与函数
array
普通数组定义方式:
数组名=(v1 v2 v3 v4 v5 v6)
#索引 0 1 2 3 4 5
数组名=(v1 v2 v3 v4 v5 [20]=v6)
#索引 0 1 2 3 4 20
数组名[0]=v1
数组名[1]=v2
数组名[2]=v3
数组名[3]=v4
关联数组定义方式:类似哈希表
declar -A 数组名#此处需要提前声明为关联数组
数组名=([name]=jack [age]=18)
#索引 name age
function
两处注释一定要注意
函数名() {#内部出现的位置参数是函数调用时的参数
函数块
}
函数名 参数#此处出现的位置参数是脚本调用时的参数
fuction 函数名 {
函数块
}
函数名 参数
#!/bin/bash
Factorial() {
val=1
for i in `seq $1` #函数位置变量,$1指函数调用时的参数
do
val=$(($val*$i))
done
echo "$val"
}
result=`Factorial $1` #sh脚本位置变量,此处的$1指的是脚本的参数
echo "$result"
seq 8指的是1 2 3 4 5 6 7 8
#!/bin/bash
test(){
return $[2*$1]
}
test $1
res=$?
echo "$res"
return 返回的是程序或者函数运行完后的返回值,echo是函数运行完后输出想要的结果可以把此结果赋值给另一个变量来保存可以当返回值来用
把返回值存入数组
返回数组
#!/bin/bash
num=(4 5 6)
array() {
b=66 #b是全局变量
local c=66 #c是局部变量
for i in $@ #所有参数 #注释与代码间最好有空格,这样避免出错
do
val[j++]=$i
done
echo "${val[*]}"
}
#array ${num[*]}
#echo 可以输出b,不能输出c因为c是局部的
result=`array ${num[*]}` #nums所有值,所有元素
#echo 不能输出b,因为上述过程是在子shell执行的
echo "$result"
注释与代码间最好有空格,这样避免出错