# 位置变量的简单使用 [root@centos7 ~]# cat /shell/arg.sh #!/bin/bash # ********************************************************** # * Filename : arg.sh # * Author : Herbert # * Version : 1.0 # * Email : wuhaolam@163.com # * Website : wuhaolam.github.io # * Date : 2022-10-03 # * Description : 位置变量的简单使用 # ********************************************************** echo"1st arg is $1" echo"2st arg is $2" echo"3st arg is $3" echo"10st arg is ${10}" echo"11st arg is ${11}"
echo"The number of arg is $#" echo"All args are: $*" echo"All args are: $@" echo"The script path is $0" echo"The scriptname is `basename $0`" [root@centos7 shell]# bash /shell/arg.sh {a..z} 1st arg is a 2st arg is b 3st arg is c 10st arg is j 11st arg is k The number of arg is 26 All args are: a b c d e f g h i j k l m n o p q r s t u v w x y z All args are: a b c d e f g h i j k l m n o p q r s t u v w x y z The script path is /shell/arg.sh The scriptname is arg.sh
## $*将所有的参数作为一个整体进行传递,而$@将所有参数当作独立的参数全部传递过去 [root@centos7 shell]# bash f1.sh a b c f1.sh: all args are a b c f1.sh: all args are a b c file.sh: 1st arg is a b c [root@centos7 shell]# bash f2.sh a b c f2.sh: all args are a b c f2.sh: all args are a b c file.sh: 1st arg is a
-u 在扩展一个没有设置的变量时,显示错误信息,等同 set -o nounset -e 如果一个命令返回一个非0退出状态值就退出,等同 set -o errexit -o option 显示,打开或关闭选项 set -o 显示选项 set -o 选项 打开选项 set +o 选项 关闭选项 -x 当执行命令时,打印命令及其参数,类似 bash -x
[root@Rocky8-mini ~]# set -o allexport off braceexpand on emacs on errexit off errtrace off functrace off hashall off histexpand on history on ignoreeof off interactive-comments on keyword off monitor on noclobber off noexec off noglob off nolog off notify off nounset off onecmd off physical off pipefail off posix off privileged off verbose off vi off xtrace off
ARITHMETIC EVALUATION The shell allows arithmetic expressions to be evaluated, under certain circumstances (see the let and declarebuiltin commands and Arithmetic Expansion). Evaluation is donein fixed-width integers with no check for overflow, though division by 0 is trapped and flagged as an error. The operators and their precedence, associativity, and values are the same as in the C language. The following list of operators is grouped into levels of equal-precedence operators. The levels are listed in order of decreasing precedence.
* / % multiplication, division, remainder, %表示取模,即取余数,示例:9%4=1,5%3=2 + - addition, subtraction i++ i-- variable post-increment and post-decrement ++i --i variable pre-increment and pre-decrement = *= /= %= += -= <<= >>= &= ^= |= assignment - + unary minus and plus ! ~ logical and bitwise negation ** exponentiation 乘方,即指数运算 << >> left and right bitwise shifts <= >= < > comparison == != equality and inequality & bitwise AND | bitwise OR ^ bitwise exclusive OR && logical AND || logical OR expr?expr:expr conditional operator expr1 , expr2 comma
算数运算实现
1 2 3 4 5 6 7 8 9 10 11 12 13
(1) let var=算术表达式 (2) ((var=算术表达式)) (3) var=$[算术表达式] (4) var=$((算术表达式)) (5) var=$(expr arg1 arg2 arg3 ...) (6) declare -i var = 数值 (7) echo'算术表达式' | bc
随机数生成器 $RANDOM ooa random integer between 0 and 32767 is generated. ## 注:乘法符号在有些场景需要转义 # mul=$(expr $num1 \* $num2)
[root@centos7 ~]# help test test: test [expr] Evaluate conditional expression. Exits with a status of 0 (true) or 1 (false) depending on the evaluation of EXPR. Expressions may be unary or binary. Unary expressions are often used to examine the status of a file. There are string operators and numeric comparison operators as well. The behavior of test depends on the number of arguments. Read the bash manual page for the complete specification. File operators: -a FILE True if file exists. -b FILE True if file is block special. -c FILE True if file is character special. -d FILE True if file is a directory. -e FILE True if file exists. -f FILE True if file exists and is a regular file. -g FILE True if file is set-group-id. -h FILE True if file is a symbolic link. -L FILE True if file is a symbolic link. -k FILE True if file has its `sticky' bit set. -p FILE True if file is a named pipe. -r FILE True if file is readable by you. -s FILE True if file exists and is not empty. -S FILE True if file is a socket. -t FD True if FD is opened on a terminal. -u FILE True if the file is set-user-id. -w FILE True if the file is writable by you. -x FILE True if the file is executable by you. -O FILE True if the file is effectively owned by you. -G FILE True if the file is effectively owned by your group. -N FILE True if the file has been modified since it was last read. FILE1 -nt FILE2 True if file1 is newer than file2 (according to modification date). FILE1 -ot FILE2 True if file1 is older than file2. FILE1 -ef FILE2 True if file1 is a hard link to file2. String operators: -z STRING True if string is empty. -n STRING STRING True if string is not empty. STRING1 = STRING2 True if the strings are equal. STRING1 != STRING2 True if the strings are not equal. STRING1 < STRING2 True if STRING1 sorts before STRING2 lexicographically. STRING1 > STRING2 True if STRING1 sorts after STRING2 lexicographically. Other operators: -o OPTION True if the shell option OPTION is enabled. -v VAR True if the shell variable VAR is set ! EXPR True if expr is false. EXPR1 -a EXPR2 True if both expr1 AND expr2 are true. EXPR1 -o EXPR2 True if either expr1 OR expr2 is true. arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne, -lt, -le, -gt, or -ge. Arithmetic binary operators return true if ARG1 is equal, not-equal, less-than, less-than-or-equal, greater-than, or greater-than-or-equal than ARG2. Exit Status: Returns success if EXPR evaluates to true; fails if EXPR evaluates to false or an invalid argument is given.
1.10.1 变量测试
1 2 3 4 5 6 7 8 9
# 判断变量是否定义 [ -v NAME ] # 判断变量是否定义并且是名称引用,bash 4.4新特性 [ -R NAME ]
# 搜索(list) [root@centos7 ~]# man bash (list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The return status is the exit status of list. { list; } list is simply executed in the current shell environment. list must be terminated with a newline or semicolon. This is known as a group command. The return status is the exit status of list. Note that unlike the metacharacters ( and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized. Since they do not cause a word break, they must be separated from list by whitespace or another shell metacharacter.
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
[root@centos7 ~]# name=Tom;(echo $name;name=Jerry;echo $name);echo $name Tom Jerry Tom
[root@centos7 ~]# name=Tom;{ echo $name;name=Jerry;echo $name; };echo $name Tom Jerry Jerry
常见选项: -p 指定要显示的提示 -s 静默输入,一般用于密码 -n N 指定输入的字符长度N -d '字符' 输入结束符 -t N TIMEOUT为N秒
示例
1 2 3 4 5 6 7 8 9 10 11
[root@centos7 ~]# echo $REPLY
[root@centos7 ~]# read TEST [root@centos7 ~]# echo $REPLY TEST
[root@centos7 ~]# read -p "Please input your name: " NAME Please input your name: Tom [root@centos7 ~]# echo $NAME Tom
示例:read命令使用管道符时的注意点
1 2 3 4 5 6 7 8
Pipelines A pipeline is a sequence of one or more commands separated by one of the control operators | or |&. [root@Rocky8-mini ~]# echo Jerry | read NAME [root@Rocky8-mini ~]# echo $NAME
[root@Rocky8-mini ~]# echo Jerry | { read NAME; echo $NAME; } Jerry
[root@Centos7-mini ~]# cat filetype.sh #!/bin/bash read -p "Please input a file path: " ROUTE TYPE=`ls -l -d "$ROUTE" | head -c1` if [ "$TYPE" = "-" ];then echo"$ROUTE is a common file!" elif [ "$TYPE" = "d" ];then echo"$ROUTE is a directory file!" elif [ "$TYPE" = "p" ];then echo"$ROUTE is a Pipe file!" else echo"$ROUTE is a other file!" fi
if [[ $INTNUM =~ ^[0-9]+$ ]];then echo"$INTNUM 是一个正整数!" else echo"$INTNUM 不是一个正整数!" fi
3.2 循环
3.2.1 循环 for
格式1
1 2 3 4 5 6 7 8 9 10
#方式1 for 变量名 in 列表;do 循环体 done
#方式2 for 变量名 in 列表 do 循环体 done
for 循环列表生成方式
直接给出列表
整数列表
1 2
{star..end} $(seq [start [step]] end)
返回列表的命令
1
$(COMMAND)
使用glob,如:*.sh
变量引用,如:$@, $*, $#
1 2 3 4 5 6 7 8 9 10 11 12 13
# 当不指定列表时,默认使用位置变量 $@ [root@Rocky8-mini ~]# cat test.sh #!/bin/bash for NAME; do echo$NAME done [root@Rocky8-mini ~]# bash -x test.sh Tom Jerry + for NAME in"$@" + echo Tom Tom + for NAME in"$@" + echo Jerry Jerry
示例:
1 2 3 4 5
# 计算 1+2+3+...+100 的结果 [root@Rocky8-mini ~]# sum=0;for i in {1..100};do sum=$[$sum+$i];done;echo "sum=$sum" sum=5050 [root@Rocky8-mini ~]# seq -s+ 100 | bc 5050
示例:
1 2 3 4 5
# 100以内的奇数之和 [root@Rocky8-mini ~]# sum=0;for i in {1..100..2};do let sum=sum+i;done;echo "sum=$sum" sum=2500 [root@Rocky8-mini ~]# seq -s+ 1 2 100 | bc 2500
实例:自定义输入数字计算之和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[root@centos7 shell]#cat for_sum.sh #!/bin/bash # ********************************************************** # * Filename : for_sum.sh # * Author : Herbert # * Version : 1.0 # * Email : wuhaolam@163.com # * Website : wuhaolam.github.io # * Date : 2022-10-09 # * Description : 接收命令行传来的参数计算之和 # ********************************************************** sum=0 for i in $*; do sum=$[sum+i] done echo"sum=$sum" [root@centos7 shell]#bash for_sum.sh 1 2 3 4 5 sum=15
实例:传递用户名参数自动创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[root@centos7 shell]#cat CreateUser.sh #!/bin/bash # ********************************************************** # * Filename : CreateUser.sh # * Author : Herbert # * Version : 1.0 # * Email : wuhaolam@163.com # * Website : wuhaolam.github.io # * Date : 2022-10-09 # * Description : Create Users in Batchers # ********************************************************** [ $# -eq 0 ] && { echo"USAGE: CreateUser.sh USERNAME ...";exit 1; } for USERS;do id$USERS &> /dev/null && echo"user $USERS already exists" || { useradd $USERS;echo"'$USERS' user created successfully!"; } done [root@centos7 shell]#bash CreateUser.sh Tom Jerry 'Tom' user created successfully! 'Jerry' user created successfully!
# 方式一 [root@centos7 shell]#cat MultiplicationTable.sh #!/bin/bash for i in {1..9};do for j in `seq$i`;do echo -e "$j*$i=$[j*i]\t\c" done echo done
# 方式二,printf 打印九九乘法表 [root@centos7 shell]#cat MultiplicationTable.sh #!/bin/bash for i in {1..9};do for j in `seq$i`;do printf"%s*%s=%d\t"$j$i $[i*j] done printf"\n" done
# 方式三,打印多彩九九乘法表 [root@centos7 shell]#cat MultiplicationTable.sh #!/bin/bash for i in {1..9};do for j in `seq$i`;do echo -e "\E[1;$[RANDOM%7+31]m$j*$i=$[j*i]\t\c\E[0m" done echo done
生产案例:将指定目录下文件所有文件后缀名改为bak后缀
1 2 3 4 5 6 7 8
[root@centos7 shell]#cat suffix.sh #!/bin/bash DIR=/data/test cd$DIR || { echo"Can not access to!";exit 1; } for FILE in *;do PRE=`echo$FILE | grep -Eo ".*\."` mv$FILE${PRE}bak done
[root@centos7 shell]#cat ScanHost.sh #!/bin/bash NET=192.168.0 for ID in {1..254};do fping $NET.$ID &> /dev/null && echo"$NET.$ID is alived" | tee -a /tmp/ip_alived.log || echo"$NET.$ID is down" done
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash cd /var for FILE in /var/*;do TYPE=`ls -l -d "$FILE" | head -c1` case"$TYPE"in "-") echo"$FILE is a test file!" ;; "b") echo"$FILE is a Block file!" ;; "c") echo"$FILE is a Character file!" ;; "l") echo"$FILE is a Link file!" ;; "p") echo"$FILE is a Pipe file!" ;; "d") echo"$FILE is a Directory file!" ;; "s") echo"$FILE is a Socket file!" ;; *) echo"$FILE is a other file!" ;; esac done
2、添加10个用户user1-user10,密码为8位随机字符
1 2 3 4 5 6 7 8 9 10
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash for i in {1..10};do NewUser="user$i" id"$NewUser" &> /dev/null && { echo"$NewUser is exist!";continue; } useradd "$NewUser" Password=`cat /dev/urandom | tr -dc [[:alnum:]] | head -c8` echo"$Password" | passwd --stdin "$NewUser" > /dev/null done echo -e "\E[1;32mUsers create Successfully!\E[0m"
[root@Centos6-mini ~]# cat test.sh #!/bin/bash set -e set -u cd /etc/rc.d/rc3.d/ for FILE in `ls`;do Character=`echo"$FILE" | head -c1` if [ "$Character" = 'K' ];then echo"$FILE stop" else echo"$FILE start" fi done
4、编写脚本,提示输入正整数n的值,计算1+2+…+n的总和
1 2 3 4 5 6 7 8
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash read -p "Please input a positive integer: " N sum=0 for i in `seq$N`;do letsum=$sum+$i done echo"1+..+$N equal is $sum"
5、计算100以内所有能被3整除的整数之和
1 2 3 4 5 6 7 8 9 10
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash sum=0 for i inecho {3..100};do RESULT=$[$i%3] if [ "$RESULT" -eq 0 ];then letsum=$sum+$i fi done echo -e "\E[1;32m100以内所有能被3整除的整数之和为: $sum\E[0m"
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash sum=1 for (( i=2; i<=10; i++ )) do sum=$[($sum+1)*2] done echo"The monkey picked $sum peaches on the first day" [root@Rocky8-mini ~]#bash test.sh The monkey picked 1534 peaches on the first day
3.2.2 循环 while
格式:
1 2 3 4 5 6 7 8 9 10 11 12
while CONDITION; do 循环体 done
# 无限循环 whiletrue;do 循环体 done
while :;do 循环体 done
实例:磁盘检查并发出邮件警告
1 2 3 4 5 6 7 8 9 10 11
# 实现报警功能需提前设置好报警功能 [root@centos7 ~]#cat while_check_disk.sh #!/bin/bash WARNING=80 whiletrue;do CAPACITY=`df -Th | awk '/\/dev\/sd/{print $6}' | cut -d"%" -f1 | sort -nr | head -n1` if [ $CAPACITY -ge $WARNING ];then echo"Disk will be full from `hostname -I`" | mail -s "Linux disk check" wuhaolam@163.com fi sleep 10 done
练习
1、编写脚本,求100以内所有正奇数之和
1 2 3 4 5 6 7 8 9
[root@Rocky8-mini ~]# cat test.sh #!/bin/bash i=1 sum=0 while [ $i -le 100 ];do sum=$[sum+i] i=$[i+2] done echo"The sum of odd numbers(1~100) is $sum"
[root@Rocky8-mini ~]# cat test.sh #!/bin/bash for words in efbaf275cd 4be9c40b8b 44b2395c46 f8c8873ce0 b902c16c8b ad865d2f63;do whiletrue;do INIT_VALUE=$RANDOM PW=`echo$INIT_VALUE | md5sum | cut -c1-10` if [ "$words" = "$PW" ];then echo"$words initial value is $INIT_VALUE" break fi done done [root@Rocky8-mini ~]# bash test.sh efbaf275cd initial value is 15000 4be9c40b8b initial value is 12000 44b2395c46 initial value is 9000 f8c8873ce0 initial value is 6000 b902c16c8b initial value is 3000 ad865d2f63 initial value is 1000
3.2.3 循环 until
格式:
1 2 3 4 5 6 7 8 9 10 11 12
until CONDITION; do 循环体 done
# 无限循环 until false; do 循环体 done
说明: 进入条件 CONDITION 为 false 推出条件 CONDITION 为 true
示例
1 2
[root@Rocky8-mini ~]# sum=0;i=1;until [ $i -gt 100 ];do let sum=sum+i; let i++;done;echo $sum 5050
3.2.4 continue 语句
continue [N]:提前结束第N层的本轮循环,直接进入下一轮判断;最内层为第1层
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[root@Rocky8-mini ~]# cat test.sh #!/bin/bash for i in {1..5};do if [ $i -eq 3 ];then continue echo$i else echo$i fi done [root@Rocky8-mini ~]# bash test.sh 1 2 4 5
3.2.5 break 语句
break[N]:提前结束第N层整个循环,最内层为第1层
示例
1 2 3 4 5 6 7 8 9 10 11 12 13
[root@Rocky8-mini ~]# cat test.sh #!/bin/bash for i in {1..5};do if [ $i -eq 3 ];then break echo$i else echo$i fi done [root@Rocky8-mini ~]# bash test.sh 1 2
whileread -p "Please input your number[0~9]: " INPUT ;do if [ $INPUT -eq $NUM ];then echo"Congratulations on your correct guess!" break elif [ $INPUT -gt $NUM ];then echo"Too big, again please!" else echo"Too small, again please!" fi done
3.2.6 shift命令
shift [n] 用于将参数列表 list 左移指定次数,缺省为左移一次。
当参数列表 list 被移动,最左端的那个参数就从列表中删除。while循环遍历位置参数列表时,常用到 shift
示例1
1 2 3 4 5 6 7 8 9 10 11 12
[root@Rocky8-mini ~]# cat test.sh #!/bin/bash until [ -z "$1" ];do echo"$1" shift done [root@Rocky8-mini ~]# bash test.sh a b c d e a b c d e
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# shift 批量创建用户 [root@Rocky8-mini ~]# cat batch_create_user.sh #!/bin/bash while [ "$1" ];do ifid$1 &> /dev/null;then echo$1 user is exist else useradd $1 echo"$1 user create successfully!" fi shift done [root@Rocky8-mini ~]# bash batch_create_user.sh Tom Jerry Tom user create successfully! Jerry user create successfully!
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash [ $# -eq 0 ] && echo"Please input at lease one parameter: '/etc/fstab ...'" for FILE in"$@";do Lines=`cat$FILE | wc -l` echo"The number of lines for '$FILE' is $Lines." done
3、用二个以上的数字为参数,显示其中的最大值和最小值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[root@Rocky8-mini ~]#cat test.sh #!/bin/bash [ $# -le 2 ] && { echo"Please input at least two parameters!";exit 1; }
MAX=$1 MIN=$1 for NUM in"$@";do if [ $MAX -lt $NUM ];then MAX=$NUM fi if [ $MIN -gt $NUM ];then MIN=$NUM fi done echo"'$*',the MAX number is $MAX; the MIN number is $MIN."
3.2.7 while 特殊用法 while read
while 循环的特殊用法,遍历文件或文本的每一行
1 2 3 4 5
whileread LINE;do loop body done < /PATH/SOMEFILE
# 依次读取/PATH/SOMEFILE文件中的每一行,且将行赋值给变量LINE
示例
1 2 3 4 5 6 7 8
[root@Rocky8-mini ~]# echo Jerry | read x;echo $x
[root@Rocky8-mini ~]# echo Jerry | { read x;echo $x; } Jerry [root@Rocky8-mini ~]# echo Jerry | while read X;do echo $X;done Jerry [root@Rocky8-mini ~]# echo Tom Jerry Snoopy | while read X Y Z; do echo $X $Y $Z;done Tom Jerry Snoopy
df | awk -F" +|%"'/^\/dev\/sd/{print $1,$5}' | whileread DEVICE UTILIZATION;do if [ $UTILIZATION -ge $WARNING ];then echo"$DEVICE will be full, Utilization: $UTILIZATION%" | mail -s "Linux Disk Warning"$MAIL fi done
[root@centos7 shell]#cat select_menu.sh #!/bin/bash # ********************************************************** # * Filename : select_menu.sh # * Author : Herbert # * Version : 1.0 # * Email : wuhaolam@163.com # * Website : wuhaolam.github.io # * Date : 2022-10-25 # * Description : Use 'select' command accomplish order function # ********************************************************** sum=0 PS3="Here is the menu.Please take you order(1-6): " select MENU in 老母鸡汤 紫薯饭 毛豆烧鸡 竹笋鸡翅 蒸蛋 点菜结束;do case$REPLYin 1) echo"$MENU prince is ¥16" letsum=sum+16 ;; 2) echo"$MENU prince is ¥3" letsum=sum+3 ;; 3) echo"$MENU prince is ¥15" letsum=sum+15 ;; 4) echo"$MENU prince is ¥12" letsum=sum+12 ;; 5) echo"$MENU prince is ¥6" letsum=sum+6 ;; 6) echo"点菜结束" break ;; *) echo"Input error,please reselect!" ;; esac done echo"A total of consumption: ¥$sum"
# 打印一个进度条 [root@Rocky8-mini ~]#cat test.sh #!/bin/bash functionprogress_bar() { local char="$1" local number="$2" local c for ((c=0; c<number; c++)); do printf"$char" done }
[root@Rocky8-mini ~]# read -a names wang wu zhou zheng [root@Rocky8-mini ~]# echo ${names[*]} wang wu zhou zheng
6.4 显示所有数组
显示所有数组
1 2 3 4 5 6 7 8 9 10 11 12 13
declare -a
[root@Rocky8-mini ~]# declare -a declare -a BASH_ARGC=() declare -a BASH_ARGV=() declare -a BASH_COMPLETION_VERSINFO=([0]="2" [1]="7") declare -a BASH_LINENO=() declare -a BASH_SOURCE=() declare -ar BASH_VERSINFO=([0]="4" [1]="4" [2]="20" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu") declare -a DIRSTACK=() declare -a FUNCNAME declare -a GROUPS=() declare -a PIPESTATUS=([0]="2")
6.5 引用数组
1 2 3 4 5 6 7 8
${ARRAY_NAME[INDEX]} # 如果省略[INDEX],表示引用下标为0的元素
[root@Rocky8-mini ~]# name=("Tom" "Jerry" "Snoopy") [root@Rocky8-mini ~]# echo ${name} Tom [root@Rocky8-mini ~]# echo ${name[1]} Jerry
引用数组中所有元素
1 2 3 4 5
${ARRAY_NAME[*]} ${ARRAY_NAME[@]}
[root@Rocky8-mini ~]# echo ${name[*]} Tom Jerry Snoopy
[root@Rocky8-mini ~]# unset title [root@Rocky8-mini ~]# name=${title-wh};echo $name wh
8.2 高级变量用法-有类型变量
1 2 3 4 5 6 7 8 9 10 11 12 13
declare [选项] 变量名
选项: -r 声明或显示只读变量 -i 将变量定义为整型数 -a 将变量定义为数组 -A 将变量定义为关联数组 -f 显示已定义的所有函数名及其内容 -F 仅显示已定义的所有函数名 -x 声明或显示环境变量和函数,相当于export -l 声明变量为小写字母 将变量中的大写字母都转换成小写字母 -u 声明变量为大写字母 将变量中的小写字母都转换成大写字母 -n make NAME a reference to the variable named by its value