CherieLi Student

shell 学习

2022-11-01
CherieLi

$@:表示脚本参数的内容。

$#:表示脚本参数的个数。

$?: 表示函数的执行状态

$0: 脚本名本身

$?: 最后一个后台进程的ID号

$1: 表示第一个参数

${10}: 第十个参数,当位置参数的个数大于9时,需要用${}括起来标识

获取shell函数结果:$?

1)用变量接收函数返回值,函数用echo等标准输出将要返回的东西打印出来。

2)用$?来接收函数的执行状态,但是$?要紧跟在函数调用处的后面。

打印日期

date +"%Y-%m-%d %H:%M:%S”

function log()
 {
       echo "[$(date "+%Y-%m-%d %H:%M:%S.%N")][$$] $@"
 }

注意点:

数值太大不可为算数计算的基:

如果数字是以0开头的,bash误以为是进制,如month=08,八月,bash默认为八进制,若要转为10进制,需要这样写10#${month}

https://codeantenna.com/a/OVRAo1GRqC

计算差量时间

local start_time=$(date +%s -d '2017-09-01 12:00:00')
sleep 1500
local current_time=$(date +%s -d '2017-09-01 12:00:00')
local delta_time=`expr $current_time - $start_time`

date +%Y%m%d //显示前天年月日

date +%Y%m%d –date=”+1 day” //显示前一天的日期

date +%Y%m%d –date=”-1 day” //显示后一天的日期

date +%s //从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数(时间戳)

help

function help()
{
cat << EOF
------------------------------help---------------------------------
EOF
}

case

case $action in
	aaa)
	    aaa
	 ;;
	bbb)
	    bbb
	 ;;
	ccc)
	    ccc
	 ;;
    help)
        help
     ;;
    *)
esac

linux shell 指令 诸如-d, -f, -e之类的判断表达式

文件比较运算符
-e filename 	如果 filename存在,则为真 	[ -e /var/log/syslog ]
-d filename 	如果 filename为目录,则为真 	[ -d /tmp/mydir ]
-f filename 	如果 filename为常规文件,则为真 	[ -f /usr/bin/grep ]
-L filename 	如果 filename为符号链接,则为真 	[ -L /usr/bin/grep ]
-r filename 	如果 filename可读,则为真 	[ -r /var/log/syslog ]
-w filename 	如果 filename可写,则为真 	[ -w /var/mytmp.txt ]
-x filename 	如果 filename可执行,则为真 	[ -L /usr/bin/grep ]
filename1-nt filename2 	如果 filename1比 filename2新,则为真 	[ /tmp/install/etc/services -nt /etc/services ]
filename1-ot filename2 	如果 filename1比 filename2旧,则为真 	[ /boot/bzImage -ot arch/i386/boot/bzImage ]
字符串比较运算符 (请注意引号的使用,这是防止空格扰乱代码的好方法)
-z string 	如果 string长度为零,则为真 	[ -z "$myvar" ]
-n string 	如果 string长度非零,则为真 	[ -n "$myvar" ]
string1= string2 	如果 string1与 string2相同,则为真 	[ "$myvar" = "one two three" ]
string1!= string2 	如果 string1与 string2不同,则为真 	[ "$myvar" != "one two three" ]
算术比较运算符
num1-eq num2 	等于	[ 3 -eq $mynum ]
num1-ne num2 	不等于	[ 3 -ne $mynum ]
num1-lt num2 	小于	[ 3 -lt $mynum ]
num1-le num2 	小于或等于	[ 3 -le $mynum ]
num1-gt num2 	大于	[ 3 -gt $mynum ]
num1-ge num2 	大于或等于	[ 3 -ge $mynum ]

-b file检测文件是否是块设备文件,如果是,则返回 true。

-c file检测文件是否是字符设备文件,如果是,则返回 true。

-d file检测文件是否是目录,如果是,则返回true。

-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true。

-g file检测文件是否设置了 SGID 位,如果是,则返回 true。

-k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回true。

-p file检测文件是否是具名管道,如果是,则返回 true。

-u file检测文件是否设置了SUID 位,如果是,则返回true。

-r file检测文件是否可读,如果是,则返回true。

-w file检测文件是否可写,如果是,则返回 true。

-x file检测文件是否可执行,如果是,则返回 true。

-s file检测文件是否为空(文件大小是否大于0),不为空返回true。

-e file检测文件(包括目录)是否存在,如果是,则返回 true。

=检测两个字符串是否相等,相等返回true。

!=检测两个字符串是否相等,不相等返回true。

-z检测字符串长度是否为0,为0返回true。

-n检测字符串长度是否为0,不为0返回true。

str检测字符串是否为空,不为空返回 true。

shell运算

https://blog.csdn.net/shimazhuge/article/details/38703523

关系运算

关系运算符只支持数字,不支持字符串,除非字符串的值是数字

-eq:equal

-ne:not equal

-gt:greater than

-lt:less than

-ge:greater or equal

-le:less or equal

布尔运算

#-o 或运算 or

#-a 与运算 and

算术运算

要在Linux Bash Shell中进行算术运算,有三种写法

一、使用let命令

let “sum=3+5” # sum <- 8 等号右边以及运算符和括号的两边都不能有空格

二、使用expr命令

sum=`expr 2 - 5` # sum <- -3

注意: 乘号(*), 左括号( , 右括号)必须使用反斜杠(\)转义expr右边以及运算符和括号的两边必须有空格; 如果采用紧凑的写法(紧凑格式可以不对*, (, )进行转义), 则返回算术表达式.

三、使用(( … )) 的形式

sum=$((3+5)) # sum <- 8

无需对运算符和括号做转义处理,也可以采用松散或紧凑的格式.

逻辑运算

! 逻辑非

-a 逻辑与

-o 逻辑或

变量自增

#!/bin/sh #本脚本测试shell脚本中整型变量自增 加1的几种方法

#定义整型变量 a=1 echo $a

#第一种整型变量自增方式 a=$(($a+1)) echo $a

#第二种整型变量自增方式 a=$[$a+1] echo $a

#第三种整型变量自增方式 a=`expr $a + 1` echo $a

#第四种整型变量自增方式 let a++ echo $a

#第五种整型变量自增方式 let a+=1 echo $a

#第六种整型变量自增方式 ((a++)) echo $a

循环

https://blog.csdn.net/taiyang1987912/article/details/38929069

for 循环(任何空白字符都可以作为其读取的分隔符)

while 循环(使用换行符作为行标记)

while循环读取文件中的内容有两种写法,一种是管道符,一种是重定向

管道符:

cat $file_name | while read line
do
   #####
done

重定向:

while read line
do
   #####
done < $file_name

until 循环

select 循环

作用域问题

https://blog.csdn.net/xuejianbest/article/details/98486256

https://blog.csdn.net/Ls4034/article/details/76005929

Shell变量while循环内改变无法传递到循环外

https://blog.csdn.net/shawhe/article/details/65631543?spm=1001.2101.3001.6650.14&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-14.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-14.no_search_link

shell多线程执行程序

Shell中并没有真正意义的多线程,要实现多线程可以启动多个后端进程,最大程度利用cpu性能。

(1) 顺序执行的代码

(2) 并行代码

使用’&’+wait 实现“多进程”实现

#!/bin/bash

date

for i in `seq 1 5`

do

{

echo "sleep 5"

sleep 5

} &

done

wait ##等待所有子后台进程结束

date

(3) 对于大量处理任务如何实现启动后台进程的数量可控?

  简单的方法可以使用2层for/while循环实现,每次wait内层循环的多个后台程序执行完成

  但是这种方式的问题是,如果内层循环有“慢节点”可能导致整个任务的执行执行时间长。

  更高级的实现可以看(4)

(4) 使用命名管道(fifo)实现每次启动后台进程数量可控。

#!/bin/bash

function my_cmd(){

t=$RANDOM

t=$[t%15]

sleep $t

echo "sleep $t s"

}

tmp_fifofile=”/tmp/$$.fifo”

mkfifo $tmp_fifofile # 新建一个fifo类型的文件

exec 6<>$tmp_fifofile # 将fd6指向fifo类型

rm $tmp_fifofile #删也可以

thread_num=5 # 最大可同时执行线程数量

job_num=100 # 任务总数

#根据线程总数量设置令牌个数

for ((i=0;i<${thread_num};i++));do

echo

done >&6

for ((i=0;i<${job_num};i++));do # 任务数量

\# 一个read -u6命令执行一次,就从fd6中减去一个回车符,然后向下执行,

\# fd6中没有回车符的时候,就停在这了,从而实现了线程数量控制

read -u6

 

\#可以把具体的需要执行的命令封装成一个函数

{

    my_cmd

} &

 

echo >&6 # 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个

done

wait

exec 6>&- # 关闭fd6

echo “over”

shell教程

https://www.runoob.com/linux/linux-shell.html

awk实现group by

https://www.cnblogs.com/hider/p/11834706.html

shell if [ “x${var}” == “x” ]中x的作用

https://blog.csdn.net/readnap/article/details/105047518

字符串比较防止空串

Bash 的算术运算

https://wangdoc.com/bash/arithmetic.html

$[]

$(())

bc

数组

declare-a Array

${Array[@]} 得到的是以空格隔开的元素值

${Array[*]}得到的是一整个字符串

引用符

4种引用符:双引号,单引号,反引号,转义符

部分引用:双引号括起来的引用,$,`,\会被解析为特殊含义

全引用:单引号括起来的引用

# 外部输入校验

校验poolid

pool_id=$1
if [[ ! "$pool_id" =~ ^[0-9]+$ ]];
then
    echo "param error: invalid pool_id."
    exit 1
fi

校验IP地址(ipv4)

if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        ip=(${ip//\./ }) # 按.分割,转成数组,方便下面的判断
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        ret=$?
fi

获取IP地址

ip addr |grep "inet "|grep -v "127.0.0.1"|awk -F'/' '{print $1}'|awk '{print $2}'

linux下一切皆文件

文件标识符也是一种”设备”,这个标识符会出现在/dev/fd目录中

主动打开的文件标识符需要主动关闭,否则除了系统重启,该文件标识符会一直被占用

shell脚本接参数优美用法

https://blog.csdn.net/ygqygq2/article/details/72822250

Linux Shell通过fifo实现多进程并发以及并发数控制

https://beachboyy.blog.csdn.net/article/details/85064151?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

输入以斜杠/分隔符

# 输入格式:121.37.63.0/24,223.117.173.0/24

#!/bin/bash

string=$1

array=(${string//,/ })

for var in ${array[@]}

do

iptables -D INPUT -p tcp –dport 443 -s $var -j DROP

iptables -D INPUT -p tcp –dport 80 -s $var -j DROP

done

统计shell脚本执行时间

1.用date相减

2.用time工具

检查进程状态(S、T状态)

ps -eo s,cmd grep 进程名
ps -aux grep 进程名

检查进程运行时间

ps -eo etime,comm | 进程名

ps -eo pid,lstart,etime grep [进程id]

exit与return的区别

https://cloud.tencent.com/developer/article/1398514

(1)作用不同。exit是结束一个进程,它将删除进程使用的内存空间,同时把错误信息返回父进程。 而return是返回函数值并退出函数;
(2)语义层级不同。 return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束;
(3)使用方法不同。return一般用在函数方法体内,exit可以出现Shell脚本中的任意位置。
exit exit会附带清理工作,比如全局对象、静态对象的析构,别的线程还在跑,很容易发生一些难以预测的结果。(代码中尽量不要用) exit的清理工作还没做完,进程不会退出,别的线程还在跑,一访问被析构掉的静态对象就core了

demo

#!/bin/bash
echo "第一个参数为:$1";
echo "第二个参数为:$2";
for i in "$@"; 
do    
echo $i;
done
for i in "$*"; 
do    
echo $i;
done
if [ $2 ]then
echo "存在第二个参数"
else
echo "不存在第二个参数"
fi
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";

上一篇 perf 学习

下一篇 zk 学习

Comments

Content