命令历史的功能其实并不是Linux内核提供的,而是由shell提供的,命令为history
用来设置history特性
HISTSIZE
:命令历史记录的条数HISTFILE
:定义history命令历史的保存位置,默认为~/.bash_histroyHISTFILESIZE
:命令历史文件记录历史的条数HISTCONTROL
:命令历史的记录方式(1) ignoredups
:忽略连续且相同的命令(2) ignorespace
:忽略以空白字符开头的命令(3) ignoreboth
:上述两种都有格式:history [option]
option:
1. -d # [偏移量]:删除指定命令历史
2. -c:清空命令历史
3. #:显示最近#条命令历史
4. -r:读取历史文件并将内容追加到历史列表中
5. -w:将内存中的命令历史保存到文件中
6. -a: 手动追加当前会话缓冲区的命令历史至历史文件中
1. !#:重复执行第#条指令
2. !$:重复执行上一条命令
3. ESC . :调用上一条命令的参数
4. Alt . :调用上一条命令的参数
提升用户键入命令效率的功能
命令补全:如果是内部命令,因bash自带,所以可直接使用。但是外部命令就需要遍历指定路径才可以找到,这个路径是通过环境变量$PATH
设置的。bash定义的路径中自左而右的在每个路径下搜寻以用户给定名称开头或全部匹配的文件名称,第一次找到的文件即为需要执行的命令。
路径补全:通过在用户指定目录下查找可匹配的文件名称,唯一则补全。
~[USERNAME]
:展开为用户的指定的家目录{,}
:可承载一个以逗号分隔的列表,并将其展开为多个路径 示例:
/tmp/{a,b} 等价于 /tmp/a , /tmp/b
/tmp/{data,log}/file 等价于 /tmp/data/file , /tmp/log/file
bash使用特殊变量$?
保存最近一条执行状态结果
0:表示成功
1-255:表示失败
alias是shell的内建命令,与系统本身无关,需要在shell解释器下才能够运行
alias [-p] [name[=value] ...]
(1) alias:不带任何参数的alias,显示当前shell进程中定义的命令别名
(2) \:如果不想执行alias定义的别名,要在命令前加 \
(1) 仅对当前用户:~/.bashrc
(2) 对所有用户有效:/etc/bashrc
unalias [-a] name
-a:撤销所有别名
使用通配符匹配机制来实现文件名通配
1. *:任意长度的任意字符
2. ?:任意单个字符
3. []:明确指明匹配范围内的单个字符
(1) [0-9]:明确指明为匹配数字
(2) [a-z]:指明为匹配字母,不区分字符大小写
(3) [A-Z]:仅匹配大写字母
4. [^]:匹配指定范围之外的任意单个字符
5. |:或者,如 a|b 表示 a或b
1. [:digit:]:任意数字
2. [:lower:]:任意小写字母
3. [:upper:]:任意大写字母
4. [:alpha:]:任意大小写字母
5. [:alnum:]:数字和字母
6. [:space:]:空格
7. [:blank:]
8. [:cntrl:]:控制符
9. [:graph:]:图形
10. [:print:]:可打印字符
11. [:punct:]:标点符号
12. [:xdigit:]:十六进制字符
使用ctrl + KEYWORD
KEYWORD 列表:
1. l:清屏
2. a:光标跳转至命令首部
3. e:光标跳转至命令结尾
4. c:取消命令执行
5. u:删除光标之前的内容
6. k:删除包括光标所在处至命令行尾部的所有内容
用来指定程序的数据来源于何处以及程序的结果应该出入至何处
格式:COMMAND > NEW_POS ,COMMAND >> NEW_POS
1. >:覆盖重定向,意为目标文件中原有内容会被清除
2. >>: 追加重定向,意为把新数据追加在文件尾部
3. 2>:错误覆盖重定向;
4. 2>>:追加重定向错误输出。
5. &>:正确与错误都覆盖输出;
6. &>>:正确与错误都追加输出;
1. <:改变命令的数据来源为文件。
2. <<:此处文档功能(HERE Documentation):
使用格式为:cat >> /path/somewhere << EOF
1. set <+|->C:设置是否可对已存在文件执行覆盖操作,-c为禁止,只对当前shell进程有效。
2. >|:如果启用了覆盖保护,可使用此符号来完成强制覆盖
1. |:可以将上一个命令的输出信息,送给后一个命令的输入,实现组合多个小程序完成复杂任务 \\
需要注意:最后一个命令会在当前shell的子shell运行
运行过的命令,首先通过查找hash列表,不必搜索$PATH环境变量。如果命令在被hash后路径改变,就需要重新hash,不然路径已然出错。
- hash:列出hash列表
- hash -d COMMAND:删除某命令hash结果。
- hash -r:清空命令hash列表。
配置文件的功用:通过它来指定我们长期需要但是默认没有启用的功能,bash shell
也是拥有配置文件的,并且生效次序及范围也不同,可以从多个角度理解配置文件,。
/etc/profile
:/etc/profile.d/*.sh
:如果有些应用程序配置文件过大时,可以将一个配置文件分割成多个片段,每个片段用来保存一部分配置/etc/bashrc
:~/.bash_profile
:~/.bashrc
:~/.bash_profile:
profile类
:/etc/profile、/etc/profile.d/*.sh、~/.bash_profile
bashrc类
:/etc/bashrc、~/.bashrc
注:交互式登录与非交互式登录用的文件并没有严格的规定,也就是说交互式登录的shell有可能会用到bashrc类文件中的配置,非交互式登录的shell也有可能会用到profile类文件中的配置。
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
~]# source /PATH/FILE
~]# . /PATH/FILE
对于同一个变量,如果定义在多个配置文件中,那么读取次序越靠后的配置将生效
大多数的shell编程语言都是通过调用当前系统上的二进制命令,组织罗列、解释执行的。
如果想理解bash脚本编程,需要先了解以下前置的知识点。
程序是由 指令 + 数据 组成,目前来讲,编程语言有两种风格,其一为过程式编程,也叫面向过程的编程。另一种是面向对象的编程,也称为对象式编程。两种的不同之处如下:
(1)过程式编程语言:程序编写以指令为中心,只需要考虑指令是如何运行的,而后根据指令的需要来决定数据如何存储
(2)面向对象的编程语言:以数据为中心,围绕数据来组织指令
这一段比较抽象,结合现实生活的例子,分享下我自己的理解:
例子1(过程式编程语言):接到一个任务,需要把货物运送到A点,在过程式编程语言中,假如指令和数据分别对应运送方式和货物,那么首先我们就先需要设定运送方式,可使用货车、飞机等等,也就是说我们需要先确定运送方式(指令),具体货物大小、重量(数据)我都不管,等运送方式确定了后,在将货物按照这个运送方式去码放。也就是数据服务于指令。
例子2(对象式编程语言):同样运送货物,我需要先确定货物在我的仓库中如何存放更方便,比如按重量、温度等等。等货物的存放方式确定好了。在确定如何运送,比如冷藏运送、空运等等。这里运送方式就是服务于货物了
当然不同的运送方式最终到达终点的速度也不一样,就像是不同的指令算法之间的差异
对于计算机而言,它只能理解二进制执行,而对于人来讲,阅读并理解二进制指令是极为不易的,所以后来就出现了专门的编程语言,这种编程语言离二进制指令更近,但仍然需要转换。高级语言,离人类的思维方式更近。容易掌握。但是不管是高级语言还是低级语言,它都无法在机器上直接运行,都需要一种工具,可以把编程语言转换为机器可以理解的二进制语言。
(1)编译执行:编译器把整个源代码完完全全转换为二进制指令,而后再能运行,运行程序时编译器是不参与的
(2)解释执行:运行时启动一个叫解释器的程序,由解释器通篇做语法分析后,解释一句,执行一句
因为cpu只能运行二进制程序,但shell脚本是纯文本文件,不能直接在cpu上运行,这时就需要调用一个翻译,也就是在脚本起始就注明需要调用的解释器,这个机制我们叫做shebang
,比如本文所讲的shell脚本,就需要在脚本文件起始处,顶格写明#!/bin/bash
,#!
为固定格式,这就向cpu表明本脚需要调用解释器,它的绝对路径是/bin/bash
(需要注意的是解释器一定要是二进制程序)。在或者,如果你写了一个python脚本,就需要在顶格注明解释器位置,如#!/usr/bin/python
。下面示例一个简单的脚本文件:
#!/bin/bash
cat /etc/fstab
wc -l /etc/fstab
脚本运行前需要给执行权限,如果不想给执行权限也可以调用bash命令。
变量就是在程序运行中,划给他使用的一段命名内存空间,使用时需要注意变量存储的数据类型,大小
变量类型对于变量来说尤为关键,例如字符123和数值123,它们是不同的。因为计算机最小的存储单元是字节,一个字节最多可以表示256种变化,那么字符123就需要用3个字节(1用一个字节、2用一个字节、3用一个字节),那么假如123是数值,那么就需要1个字节就可以表示了,因为1个字节256种变化,已经覆盖了数值123。那么问题来了,如果你用字符123加上数值123,结果会是什么呢?
编程语言分为强类型编程语言和弱类型编程语言,对于强类型编程语言,如果计算123+123,那么两个数据都必须是数值型才可以,shell属于弱类型编程语言,它会自动将两个数据转换为字符型,帮你计算结果。但是计算出的结果是123123,它只是将字符串拼接了。
根据变量的生效范围分类
无需事先声明,可以直接使用,但不声明则为空,生效范围为当前shell进程,等当前shell进程终止就被自动撤销了
var=VALUE
var=‘$vaule’
或var="$VALUE"
双引号为弱引用,变量会被替换为变量中存储的值,强引用会保持原来的子串var=`COMMOND`
或var=$(COMMOND)
,通过反引号或$()来赋值${name}
或$name
:如果在代码段中,变量名称与其他代码相连,为了区别变量名称和代码段,可以使用一对花括号来区分出来变量名称和代码段,如无此种情况,则花括号可以省略[root@node1 ~]# set
[root@node1 ~]# unset VAR_NAME
,撤销时仅需指定变量名称,不需加$生效范围为当前shell进程及其子进程
export name=value
declare -x name=value
:声明环境变量。declare -i name=value
:声明整形数据。declare -x、export、env、printenv
$PATH、$SHELL、$UID、$HISTSIZE、$HOME、$PWD、$OLD、$HISTFILE...
生效范围为当前shell进程中某代码片段,在shell中通常指函数片段
用于让脚本在运行时,调用命令行传递给脚本的参数
$1 、$2、$3...
#!/bin/bash
echo $1
echo $2
[root@node1 ~]# ./test.sh 1 2
1
2
shift
:在脚本文件中,如果写入shift,意为把$1踢掉,后面的自动补上bash shell内置的,用来保存特殊数据的
$?
:保存上一条命令的执行返回状态码$0
:命令本身的值,也可以理解为是位置变量$#
:传递给脚本参数的个数$*
:传递给脚本的所有参数,把所有参数当做一个字符串$@
:传递给脚本的所有参数,把每个参数当独立的字符串只读变量不区分本地变量还是环境变量,只是为了定义完后,它的值不可以发生改变,它的生命周期就是当前shell进程结束为止。
[root@node1 ~]# readonly VAR_NAME
[root@node1 ~]# declare -r VAR_NAME
let var=算数表达式
:使用let 后面跟一个变量名称,=号后面直接跟算数运算表达式,这要算数结果就会被保存在变量var中let var=1+3或let var=$num1+$num2
,获取结果echo $var
var=$[算数表达式]
:=号后面跟一个$符+一对中括号,算数表达式写在中括号中,这种方式引用起来比较灵活var=$[$num1+$num2]或echo $[$num1+$num2]
var=$((算数表达式))
:$
符后面跟两对小括号,$(($num1+$num2))
var=$(expr arg1 arg2 arg3…)
:expr为固定命令,arg1为第一个数字,arg2为算数符号,arg3位第二个数字。var=$(expr 1 + 3) 或 var=$(expr 2 \* 3)
,乘号在需要转义。count=$[$count+1]等于let count+=1
count=$[$count+1]等于let count++
test EXPRESSION
:使用test命令,后面跟上需要测试的表达式[ EXPRESSION ]
:使用一对中括号,中括号两端需要有空格,这个是测试命令[[ EXPRESSION ]]
:使用两对中扩号,中括号两端需要有空格,这个是bash内建的保留字test 1 -gt 3、[ 1 -gt 3 ]、[[ 1 -gt 3 ]]
[ NUM1 -gt NUM2 ]
:大于
[ NUM1 -ge NUM2 ]
:大于等于
[ NUM1 -eq NUM2 ]
:等于
[ NUM1 -ne NUM2 ]
:不等于
[ NUM1 -lt NUM2 ]
:小于
[ NUM1 -le NUM2 ]
:小于等于
[ $VAR1 == $VAR2 ]
或[ $VAR1 = $VAR2 ]
:是否相同
[ $VAR1 > $VAR2 ]
:阿斯克码比较
[ $VAR1 < $VAR2 ]
:阿斯克码比较
[ $VAR1! = $VAR2 ]
:不等于
[ $VAR1 =~ PAT ]
:左侧字符串是否能被右侧的模式所匹配
[ -z $VAR ]
:测试字串是否为空,空位真
[ -n $name ]
:测试字串是否为不空,不空为真
字符串比较都需要使用引号
[ -a FILE ]
:测试文件是否存在,存在为真[ -e FILE ]
:测试文件是否存在,存在为真[ -b FILE ]
:文件存在且为块设备文件[ -c FILE ]
:文件存在且为字符设备文件[ -d FILE ]
:文件存在且为目录文件[ -f FILE ]
:文件存在且为普通文件[ -p FILE ]
:存在且为命名管道文件[ -S FILE ]
:存在且为套接字文件(大写S)[ -L FILE ]
或[ -h FILE ]
:存在且为符号链接文件[ -r FILE ]
:当前用户是否有读权限[ -w FILE ]
:当前用户是否有写权限[ -x FILE ]
:当前用户是否有执行权限[ -g FILE ]
:文件存在且被设置了sgid[ -u FILE ]
:文件存在且被设置了suid[ -k FILE ]
:文件存在且拥有sticky权限[ -s FILE ]
:文件是否存在且非空(小写s)[ -N FILE ]
:文件自从上一次被读取后,是否被修改过[ -O FILE ]
:当前用户是否为文件的属主[ -G FILE ]
:当前用户是否为文件的属组[ -t fd ]
:fd表示文件描述符是否已经打开且与某终端相关[ file1 -ef file2 ]
:文件是否指向同一个设备上相同的inode[ file1 -nt file2 ]
:文件1是否新与file2[ file1 -ot file2 ]
:文件1是否旧与file2[ EXPRESSION1 -a EXPRESSION2 ]
:等同于[ EXP1 ] && [ EXP2 ]
[ EXPRESSION1 -o EXPRESSION2 ]
:等同于[ EXP1 ] || [ EXP2 ]
通过罗列条件来执行代码,在多分支的if语句中,条件自上至下逐条进行判断,当条件满足时,则直接执行该分支代码,完毕后退出,后续分支将不会执行
if 条件判断; then
条件为真的执行代码
fi
if [ 1 -eq 2 ]; then
echo 1
fi
if 条件判断; then
条件为真的执行代码
else
条件为假的分支代码
fi
if [ 1 -eq 2 ]; then
echo 1
else
echo 2
fi
if 条件判断; then
条件为真的执行代码
elif 条件判断; then
条件为真的执行代码
elif 条件判断; then
条件为真的执行代码
else
都不满足时执行的代码
fi
if [ $num -eq 2 ]; then
echo 1
elif [ $num -lt 2 ]; then
echo 2
elif [ $num -gt 2 ]; then
echo 3
else
条件为假的分支代码
fi
case 变量引用 in
pat1)
分支一
;;
pat2)
分支二
;;
……
*)
默认分支
;;
esac
#!/bin/bash
#
read -p 'How old are you?' year
case $year in
20)
echo 'younger man'
;;
30)
echo 'not younger man'
;;
40)
echo 'old man'
;;
*)
echo 'ok,I know.'
;;
esac
NOTE:pat支持golb机制,不支持正则表达式
执行的机制是将列表中的元素依次赋值给变量,每赋值一次就执行一遍循环体,直到列表中的元素耗尽
for 变量名 in 列表;do
循环体
done
#!/bin/bash
#
for i in {1..254}; do
ping -w 2 192.168.1.$i &> /dev/null
done
列表的几种生成方式
直接给出值:arg1 arg2 arg3 …
整数列表:{start..end}
整数列表:$(seq 1 2 100)
:开始、增量、结束
命令结果:$(command)
glob机制:/etc/rc.d/rc3.d/K*
特殊格式的for循环用法:用两个小括号包含着变量的初始值、进入循环的条件及变量修正表达式,其中变量初始化操作只在变量进入时执行一次,变量修正表达式会在整个代码段执行完毕后就修正一次,接着在判断进入条件
for循环特殊用法格式
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式));do
循环体
done
-----------分割线------------
for循环特殊用法示例:求100以内整数和
#!/bin/bash
#
sum=0
for ((i=1;$i<=100;i++)); do
let sum+=$i
done
echo $sum
while 循环控制表达式; do
循环体
done
循环控制表达式条件为true,则执行一次循环
求一百以内偶数之和
#!/bin/bash
#
i=2
sum=0
while [ $i -lt 101 ]; do
sum=$(($sum + $i))
let i+=2
done
echo $sum
while特殊用法格式
while read line;do
循环体
done < /path/form/somefile
-----------分割线------------
while特殊用法示例:显示uid为偶数的用户
#!/bin/bash
while read line; do
uid=$(echo $line | cut -d: -f3)
if [ $[$uid%2] -eq 0 ]; then
echo $line | cut -d: -f1,3
fi
done < /etc/passwd
until 循环控制表达式; do
循环体
done
循环控制表达式条件为false,则执行一次循环
计算100以内正整数之和
#!/bin/bash
num=1
i=2
until [ $i -eq 101 ]; do
num=$(($i+$num))
let i++
done
echo $num
while 循环控制表达式;do
CMD1
...
if 条件判断;then
continue
fi
CMD2
done
正常进入while语句,当执行至if语句时做条件判断,如条件满足则做continue,表示结束本圈
循环
示例:
while 循环控制表达式;do
CMD1
...
if 条件判断;then
break
fi
CMD2
done
正常进入while语句,当执行至if语句时做条件判断,如条件满足则做break,表示结束循环提前结束本循环片段
可以将用户输入的变量对位保存,用于在脚本中与用户交互
格式:read [option] var1_name var2_name...
option
-p '提示信息':使用-p选项告知用户此处需要输入的信息格式
-t #:设置一个超时时间
-a:赋值数组
注:read命令后跟几个变量名称,那么就需要用户提供几个用空格分隔的变量值,假设用户提供的变量值不满足个数要求,那么后面的变量就会为空,再则,如果用户提供的值多于变量值的个数,那么多出来的变量值会被统一赋值给最后一个变量
格式:bash [option] script.sh
option
-n:检查语法错误
-x:单步执行
--version:版本
函数的意义就是将一段为一段具有特定功能的代码段取一个名字,随后可以在任何的代码中片段直接使用名字来引用对应的函数,是代码重用重要组件
function f_name {
……函数体……
}
f_name() {
……函数体……
}
tips:函数只有被调用才能执行,在代码片段中给定函数名即为调用。其会自动将函数名称替换为函数代码,有些函数还会带参数
在代码段中被调用时意为着函数代码被创建,使用reture命令或函数代码段最后一条命令执行完成即返回
调用函数时,在函数名后面使用空白分割参数列表即可,在函数体中可使用$1、$2…
调用位置变量,还可以使用$@,$*,$#,特殊变量
,需要注意在代码中引用函数使用的变量,并不是运行脚本时传递的参数,而是在代码段中传递给函数的参数
示例:添加10个用户
#!/bin/bash
#
adduser () {
if id $1 &> /dev/null; then
echo "user $i is exist"
return 1
else
useradd $1 && echo "user $1 add finished."
return 0
fi
}
for i in {1..10}; do
adduser user$i
done
局部变量的生命周期同函数一致,因函数创建而创建,因函数结束而结束。如果局部变量名同本地变量,需要使用local NAME=value
来声明使得两个变量互不影响
#!/bin/bash
i=1
local_var() {
local i=1
let i++
echo "function: $i"
}
local_var
echo "script: $i"
[root@centos6 sh]# bash local_var.sh
function: 2
script: 1
函数直接或间接的调用自身的实现方式,叫做函数递归。常见的递归实现场景如阶乘运算、斐波那契数列
fff() {
if [ $1 -eq 1 ]; then
echo 0
elif [ $1 -eq 2 ]; then
echo 1
else
echo "$[$(fff $[$1-1])+$(fff $[$1-2])]"
fi
}
read -p 'enter:' num
fff $num
数组可以将多个具有相似属性的元素组织在一起存储在连续的内存空间中,使用一个名称进行调用
数组其实就是多个连续的、独立的内存空间,每一个内存空间在数组中相当于一个变量,但是我们不需要给它单独的名字,而是通过数组名称+下标的方式进行引用,索引编号从0开始,标准格式为${arrary_name [index]}
bash的数组是支持稀疏格式的,比如0号元素、1号元素、4号元素都有值,而2号、3号都没值,这种不连续的
arrary_name
:数组名称[index]
:数组中可能存在多个元素,使用索引(下标)[index]
进行区分引用,下标从0开始,省略[index]
表示引用下标为0的元素${#ARRAY_NAME[*]}或${#ARRAY_NAME[@]}
:表示统计属组中的元素个数${ARRAY_NAME[@]}或${ARRAY_NAME[*]}
:表示引用属组中的所有元素${ARRAY_NAME[@]:offset:number}
:数组切片offset
:表示跳过元素个数number
:表示要取出的元素个数,number省略表示偏移量之后的所有元素declare -a ARRAY_NAME
declare -A ARRAY_NAME
:此种方式定义的数组为关联数组,普通数组的索引标号是从0开始做数值索引,但是关联数组的索引编号是自定义的,不仅仅是数值格式,需要注意的是,bash程序4.0版本之前是不支持关联数组的。在其他编程语言中关联数组也被称为键值列表定义关联数组,其索引名称(下标)不像数值索引一样有序排列,定义方式需要先声明关联数组,接着定义各个索引名称
declare -A ARRAY_NAME
ARRAY_NAME=([index_name1]=’val1’ [index_name2]=’val2’ …)
ARRAY_NAME[INDEX]="VALUE"
:一次只赋值一个元素,使用数组名称加索引名称即可。如weekdays[0]="Sunday"
ARRAY_NAME=(“VAL1” “VAL2”…)
:一次赋值多个元素,使用一对小括号进行赋值,每个值之间使用空格分隔,数组会自动给定索引号。如weekdays=("Thursday" "Sunday")
ARRAY_NAME=([0]=”VAL1” [3]=”VAL2”…)
:只赋值特定元素ARRAY_NAME[${#ARRAY[*]}]
:向数组中追加元素,需要用数组的长度作为下标unset ARRAY_NAME[index]
:删除数组中的元素read -a ARRAY_NAME
:用户交互方式赋值对变量中的字符串做切片
${var:offset:number}
${var: -#}
${var#*word}
、${var##*word}
${var%word*}
、${var%%word*}
,用法同上,但表示从右向左${var/pattern/substi}
、${var//pattern/substi}
${var/#pattern/substi}
、${var/%pattern/substi}
${var/pattern}
、${var//pattern}
${var/#pattern}
、${var/%pattern}
${var^^}
、${var,,}
^^
:表示把var中所有字符装换成大写,,
:表示把var中所有字符装换成小写${var:-value}
、${var:=value}
、${var:+value}
、${var:?err_info}
使用echo命令为将输出信息进行着色,可以修改输出信息的前景色、背景色、字体,分别使用多组数字进行控制,固定语法为\033[## word \033[0m
,其中前面的\033[##
和后面的\033[0m
为开始及结束固定语法,中间包含着需要着色的字体即可,开始及结束之间不需要空格,这里的的空格只是为了能看清格式
\033[##m
:两个#号可以替换为数字,也可以只有一个数字#!/bin/bash
# 颜色应用脚本示例,结合echo命令使用需要加-e选项
echo -e "\033[31mhello\033[0m 31m | \033[41mhello\033[0m 41m | \033[1mhello\033[0m 1m"
echo -e "\033[32mhello\033[0m 32m | \033[42mhello\033[0m 42m | \033[2mhello\033[0m 2m"
echo -e "\033[33mhello\033[0m 33m | \033[43mhello\033[0m 43m | \033[3mhello\033[0m 3m"
echo -e "\033[34mhello\033[0m 34m | \033[44mhello\033[0m 44m | \033[4mhello\033[0m 4m"
echo -e "\033[35mhello\033[0m 35m | \033[45mhello\033[0m 45m | \033[5mhello\033[0m 5m"
echo -e "\033[36mhello\033[0m 36m | \033[46mhello\033[0m 46m | \033[6mhello\033[0m 6m"
echo -e "\033[37mhello\033[0m 37m | \033[47mhello\033[0m 47m | \033[7mhello\033[0m 7m"
#!/bin/bash
多种颜色组合需要在数字之间加入分号
echo -e "\033[31;42;6mhello\033[0m 31;42;6m"
echo -e "\033[35;4mhello\033[0m 35;4m"
echo -e "\033[37;45mhello\033[0m 37;45m"
echo -e "\033[41;6mhello\033[0m 41;6m"
定义文本文件,声明参数和值,在脚本中source此文件即可
exit [n]
:脚本中一旦遇到exit命令,脚本会立即终止
[root@node1 ~]# ls -d /var/l*[0-9]*[[:lower:]]
[root@node1 ~]# ls -d /etc/[0-9]*[^0-9]
[root@node1 ~]# ls -d /etc/[^[:alpha:]][[:alpha:]]*
[root@node1 ~]# cp -r /etc/m*[^0-9] /tmp
[root@node1 ~]# cp -r /etc/*.d /tmp
[root@node1 ~]# cp -r /etc/[mnrp]*.conf /tmp
#!/bin/bash
user10=$(head -10 /etc/passwd | tail -1 | cut -d':' -f3)
user20=$(head -20 /etc/passwd | tail -1 | cut -d':' -f3)
echo "$(($user10+$user20))"
#!/bin/bash
linenum1=$(grep "^$" $1 | wc -l | cut -d' ' -f1)
linenum2=$(grep "^$" $2 | wc -l | cut -d' ' -f1)
echo "$(($linenum1+$linenum2))"
#!/bin/bash
etcnum=$(ls /etc/ | wc -l)
varnum=$(ls /var/ | wc -l)
usrnum=$(ls /usr/ | wc -l)
echo "$(($etcnum+$varnum+$usrnum))"
#!/bin/bash
[ $# -lt 1 ] && echo 'please input somepath' && exit 1 || grep '^$' $1| wc -l
#!/bin/bash
#
for name in $(ls /etc/rc.d/rc3.d); do
if [[ $name =~ ^K ]]; then
echo "$name stop"
else [[ $name =~ ^S ]]
echo "$name start"
fi
done
#!/bin/bash
#
for i in $(seq 1 1 50); do
ping -w 1 192.168.80.$i &> /dev/null
if [ $? -eq 0 ]; then
echo "192.168.80.$i is online"
else
echo "192.168.80.$i is down"
fi
done
#!/bin/bash
#
declare -i i=1
declare -i sum=0
while [ $i -le 100 ]; do
let sum+=$i
let i++
done
echo $i
echo "sum=$sum"
#!/bin/bash
#
declare -i i=2
declare -i sum=0
while [ $i -le 100 ]; do
let sum+=$i
let i+=2
done
echo $i
echo "sum=$sum"
#!/bin/bash
#
declare -i i=1
declare -i online=0
declare -i down=0
host='192.168.80.'
while [ $i -lt 20 ]; do
ping -w 2 ${host}$i &> /dev/null
if [ $? -eq 0 ]; then
let online++ && echo "${host}$i is online"
else
let down++ && echo "${host}$i in down "
fi
let i++
done
echo "online host: $online"
echo "down host: $down"
echo "$i"
#!/bin/bash
#
declare -i i=1
declare -i o=1
while [ $i -le 9 ]; do
while [ $o -le $i -a $o -le 9 ];do
echo -e -n "$o x $i = $[ $o * $i ]\t"
let o++
done
echo
let o=1
let i++
done
echo
#!/bin/bash
#
declare -i i=1
declare -i o=1
for i in {1..9};do
for o in $(seq 1 1 $i);do
echo -e -n "$o x $i = $[$i*$o]\t"
done
echo
done
#!/bin/bash
#
declare -i i=1
declare -i o=1
until [ $i -eq 10 ];do
until [ $o -gt $i -o $o -eq 10 ]; do
echo -e -n "$o x $i = $[$i*$o]\t"
let o++
done
echo
let o=1
let i++
done
#!/bin/bash
#
99cf() {
for i in $(seq 1 1 $1); do
for o in $(seq 1 1 $i);do
echo -e -n "$o x $i = $[$i*$o]\t"
done
echo
done
}
99cf $1
#!/bin/bash
#
declare -i i=1
declare -i min=60000
declare -i max=0
while [ $i -le 10 ]; do
declare -i o=$RANDOM
if [ $o -gt $max ];then
max=$o
fi
if [ $o -lt $min ];then
min=$o
fi
echo "num$i=$o"
let i++
done
echo "random min = $min"
echo "random max = $max"
#!/bin/bash
#
declare -i i=0
declare -i sum=0
until [ $i -gt 100 ]; do
let sum+=$i
let i++
done
echo "$sum"
#!/bin/bash
while read count; do
name=$(echo $count | cut -d':' -f1)
num=$(echo $count | cut -d':' -f3)
[ $[$num%2] -eq 0 ] && echo "$name: $num"
done < /etc/passwd
#!/bin/bash
while true; do
echo "=============================="
echo "cpu) show cpu information; |"
echo "mem) show memory information;|"
echo "disk) show disk information; |"
echo "quit) quit |"
echo "=============================="
read -p 'Please enter a key:' key
if [ $key == cpu ]; then
lscpu
elif [ $key == 'mem' ]; then
free -m
elif [ $key == 'disk' ]; then
fdisk -l
elif [ $key == 'quit' ]; then
echo "Bye."
break
else
echo
echo "please enter a true key."
fi
done
case语句
#!/bin/bash
while true; do
echo "=============================="
echo "cpu) show cpu information; |"
echo "mem) show memory information;|"
echo "disk) show disk information; |"
echo "quit) quit |"
echo "=============================="
read -p 'Please enter a key:' key
case $key in
cpu)
lscpu
;;
mem)
free -m
;;
disk)
fdisk -l
;;
quit)
echo "Bye."
break
;;
*)
echo
echo "please enter a true key."
;;
esac
done
#!/bin/bash
#
server_name=$(echo $0 | egrep -o "[^/]+/?$" | cut -d/ -f1)
if [ -a /var/lock/subsys/$server_name ]; then
state=0
else
state=1
fi
file=/var/lock/subsys/$server_name
case $1 in
start)
[ $state -eq 0 ] && echo "$server_name is running." && exit 0
touch $file && echo "$server_name is start ok"
;;
stop)
[ $state -ne 0 ] && echo "$server_name is not running." && exit 0
rm -f $file && echo "$server_name is stop ok"
;;
restart)
if [ $state -ne 0 ]; then
echo "$server_name is not running."
touch $file && echo "$server_name is start ok."
else
echo "$server_name is stop ok." && rm -f $file
touch $file && echo "$server_name is restart ok."
fi
;;
status)
[ $state -ne 0 ] && echo "$server_name is stopped...." && exit 0
echo "$server_name is running...."
;;
*)
echo "$server_name: invalid option $1"
echo "please use [ start | stop | restart | status ]"
;;
esac
#!/bin/bash
#
declare -a oushu
max=0
mini=40000
for i in {0..9}; do
oushu[$i]=$RANDOM
echo "$i: ${oushu[$i]}"
echo
if [ ${oushu[$i]} -gt $max ]; then
max=${oushu[$i]}
fi
if [ ${oushu[$i]} -lt $mini ]; then
mini=${oushu[$i]}
fi
done
echo "max: $max"
echo "mini: $mini"
#!/bin/bash
#
declare -a rand
declare -i max=0
declare -i min=40000
for i in {0..9}; do
rand[$i]=$RANDOM
echo ${rand[$i]}
[ ${rand[$i]} -gt $max ] && max=${rand[$i]}
[ ${rand[$i]} -lt $min ] && min=${rand[$i]}
done
echo "max: $max"
echo "min: $min"
/var/log/
目录下所有以.log
结尾的文件,要求统计其下标为偶数文件中行数之和#!/bin/bash
#
declare -i q=0
declare -i sum=0
declare -a file
declare -a file_num
for i in /var/log/*.log; do
file[$q]=$i
file_num[$q]=$(wc -l ${file[$q]} | cut -d' ' -f1)
if [ $[$q%2] -eq 0 ]; then
let sum+=${file_num[$q]}
fi
echo "${q} file: ${file[$q]} line_count: ${file_num[$q]}"
let q++
done
echo "line sum: $sum"
#!/bin/bash
#
declare -a num_seq
declare -i swap=0
read -t 10 -p "Please enter how many count: " count
[ $? -ne 0 ] && echo "You didn't enter a number, The default value is 10."
read -t 10 -p "You wang up or down? (up/down) :" order
[ $? -ne 0 ] && echo "You have no input sort, default is descending order."
${count:=10} &> /dev/null
${order:=down} &> /dev/null
echo "random list:"
for i in $(seq 0 $[$count-1]); do
num_seq[$i]=$RANDOM
echo -n "$i: ${num_seq[$i]} "
done
echo
case $order in
down)
for i in $(seq 1 ${#num_seq[@]}); do
for q in $(seq $[${#num_seq[@]}-1] -1 $i); do
if [ ${num_seq[$q]} -gt ${num_seq[$[$q-1]]} ]; then
swap=${num_seq[$[$q-1]]}
num_seq[$[${q}-1]]=${num_seq[$q]}
num_seq[$q]=$swap
fi
done
done
;;
up)
for i in $(seq 1 ${#num_seq[@]}); do
for q in $(seq $[${#num_seq[@]}-1] -1 $i); do
if [ ${num_seq[$q]} -lt ${num_seq[$[$q-1]]} ]; then
swap=${num_seq[$[$q-1]]}
num_seq[$[$q-1]]=${num_seq[$q]}
num_seq[$q]=$swap
fi
done
done
;;
*)
echo
;;
esac
echo "sort by $order"
for i in $(seq 0 $[$count-1]); do
echo -n "$i: ${num_seq[$i]} "
done
echo
#!/bin/bash
sys_root=/mnt/sysroot
while true; do
read -p "Please enter a command:" com_name
[ $com_name == quit ] && exit 0
if [ -a $com_name ]; then
echo "Start find object file."
else
echo "Command $com_name not found."
continue
fi
echo "$(file $com_name)" | grep -v "LSB" && echo 'Please enter a true command path.' && continue
while true; do
echo
file_name1=$(mktemp /tmp/filename.XXXX)
file_name2=$(mktemp /tmp/filename.XXXX)
file_name3=$(mktemp /tmp/filename.XXXX)
file_name4=$(mktemp /tmp/filename.XXXX)
file_name5=$(mktemp /tmp/filename.XXXX)
ldd $com_name >> $file_name1
line_num1=$(wc -l $file_name1| cut -d' ' -f1)
line_num2=$[$line_num1-1]
tail -n $line_num2 $file_name1 >> $file_name2
sed -in 's/[[:space:]]//g' $file_name2 > /dev/null
echo "Command $com_name need $line_num2 object file"
for i in $(cat $file_name2); do
i=$(echo $i | cut -d'>' -f2)
i=$(echo $i | cut -d'(' -f1)
echo $i
echo $i >> $file_name3
dirname $i >> $file_name4
done
read -p 'Start copy? (yes/no) ' judge
case $judge in
yes)
echo "Starting Copy"
cat $file_name4 | uniq >> $file_name5
for i in $(cat $file_name5); do
[ -a ${sys_root}${i} ] || mkdir ${sys_root}${i}
done
commond_dir=$(dirname $com_name)
[ -a ${sys_root}${commond_dir} ] || mkdir ${sys_root}${commond_dir}
[ -a ${sys_root}${com_name} ] || cp ${com_name} ${sys_root}${com_name}
for i in $(cat $file_name3); do
[ -a ${sys_root}${i} ] || cp $i ${sys_root}${i}
done
echo "Copy finish."
rm -rf $file_name1
rm -rf $file_name2
rm -rf $file_name3
rm -rf $file_name4
rm -rf $file_name5
break
;;
no)
echo "Ok~~"
break
;;
*)
echo "Bad Answer."
;;
esac
done
done