shell笔记

295 阅读6分钟

「这是我参与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="nameisgood";boy2=name is good";boy2='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"

注释与代码间最好有空格,这样避免出错