shell
基础
首行
1
2
3
4
5
|
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
#!/usr/bin/ruby
#!/usr/bin/lua
|
1
2
|
# 加执行权限
chmod +x test.sh
|
本地执行远程脚本
1
2
3
4
|
curl http://10.0.0.157/test.sh -s | bash # -s 静默
curl http://10.0.0.157/test.sh 2>/dev/null | bash
wget -qO - http://10.0.0.157/test.sh | bash
|
远程执行本地脚本
子shell:(),{}
1
2
3
4
|
临时shell环境 - 启动子shell
( 命令;命令;命令; ),在子shell中执行命令列表,退出子shell后,不影响后续环境操作。
临时shell环境 - 不启动子shell
{ 命令;命令;命令; }, 在当前shell中运行命令列表,会影响当前shell环境的后续操作。左侧要有空格,右侧要有;
|
CA创建
1
2
3
4
5
6
7
|
mkdir /tmp/CA; cd /tmp/CA
# 生成私钥
(umask 077;openssl genrsa -out ca.key 2048)
# 生成证书
openssl req -new -x509 -key ca.key -out ca.crt -days 3650
# 查看证书信息
openssl x509 -in ca.crt -noout -text
|
脚本实现
1
2
3
4
5
6
7
8
9
10
|
# 定制普通环境变量
CA_DIR="tls"
CA_DOMAIN="$1"
CA_KEY='tls.key'
CA_CRT='tls.crt'
# 创建CA证书
mkdir ${CA_DIR}
(umask 077; cd ${CA_DIR}; openssl genrsa -out tls.key 2048)
openssl req -new -x509 -key ${CA_DIR}/${CA_KEY} -out ${CA_DIR}/${CA_CRT} -subj "/CN=${CA_DOMAIN}" -days 365
|
1
|
/bin/bash ca_create.sh www.example.com
|
开写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
lscpu | sed -nr 's/^Model name: +(.*)/\1/p'
cat /proc/meminfo | head -n 1 | tr -s " " | cut -d" " -f2,3
lsblk /dev/sda | grep "^sda" | tr -s " " | cut -d" " -f4
cat /etc/os-release | sed -nr "s/^VERSION=\"(.*)\"/\1/p"
cho -e "CPU \c"
lscpu | sed -nr 's/^Model name: +(.*)/\1/p'
echo -e "Mem \c"
cat /proc/meminfo | head -n 1 | tr -s " " | cut -d" " -f2,3
echo -e "DISK \c"
lsblk /dev/sda | grep "^sda" | tr -s " " | cut -d" " -f4
echo -e "OS \c"
cat /etc/os-release | sed -nr "s/^VERSION=\"(.*)\"/\1/p"
cho -e "========================= sysinfo begin ================\n"
echo -e "CPU \c"
echo -e "\E[1;32m `lscpu | sed -nr 's/^Model name: +(.*)/\1/p'` \E[0m"
echo -e "Mem \c"
echo -e "\E[1;32m `cat /proc/meminfo | head -n 1 | tr -s " " | cut -d" " -f2,3` \E[0m"
echo -e "OS \c"
echo -e "DISK \c"
echo -e "\E[1;32m `lsblk /dev/sda | grep "^sda" | tr -s " " | cut -d" " -f4` \E[0m"
echo -e "\E[1;32m `cat /etc/os-release | sed -nr 's/^VERSION=\"(.*)\"/\1/p'` \E[0m"
echo -e "\n========================= sysinfo end =================="
|
1
2
|
bash -n test.sh # 语法检查
bash -x test.sh # 调试执行
|
变量
1
2
3
4
5
6
7
8
9
10
11
12
13
|
PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
PPID # 前进程的父进程 ID。
$$ # 当前 shell 进程的 PID
$? # 上一个命令的退出状态码。0 表示成功,非 0 表示失败。
$! # 前一个命令的PID,方便杀死
$_ # 表示上输入的一个参数.当这个命令在开头时, 打印输出文档的绝对路径名.
$- # 显示当前 shell 的选项标志。
$1,$2,....... # 第几个参数
$0 # 脚本文件名,包括路径
$* # 所有参数,一个字符串
$@ # 所有参数,每个参数独立字符
$# # 参数的个数
|
变量命名:只能使用数字、字母及下划线,且不能以数字开头
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
name='root' #直接字串
name="$USER" #变量引用
name=`COMMAND` #命令引用
name=$(COMMAND) #命令引用
"$name" # 弱引用,其中的变量引用会被替换为变量值
'$name' # 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
seq 5
1
2
3
4
5
NUM=`seq 5`
echo "$NUM"
1
2
3
4
5
echo $NUM
1 2 3 4 5
# ""会保留原格式
# 使用${}给变量圈定范围
echo ${NAME}_$AGE
# 查找全局变量F
env | grep SHELL
# 变量追加
TITLE=CTO
TITLE+=:wang
echo $TITLE
CTO:wang
#set 命令会列出所有已定义的 shell 变量和环境变量,以及它们的当前值。输出内容包括用户定义的变量、系统变量和函数。
set
# 删除变量
unset <name>
# 环境变量
export name=VALUE
# 只读变量,不可删除
readonly name=VALUE
# 位置变量
$1,$2,....... # 第几个参数
$0 # 命令本身,包括路径
$* # 所有参数,一个字符串
$@ # 所有参数,每个参数独立字符
$# # 参数的个数
# 自定义退出码
exit [n]
|
变量默认值
1
2
3
4
5
6
7
8
9
10
|
# ${变量名:-默认值}
# 有参就为参,无参就为1
a="$1"
echo ${a:-1}
# 强制默认值,无论a是什么,a都为1
${a+1}
${VAR:?error_message}
# 解释:如果 VAR 未定义或为空,则显示 error_message 并中止脚本。
|
设定变量默认值,无参数传来就为默认

展开命令行
- 把命令行分成单个命令词
- 展开别名
- 展开大括号的声明{}
- 展开波浪符声明 ~
- 命令替换$() 和 ``
- 再次把命令行分成命令词
- 展开文件通配符*、?、[abc]等等
- 准备I/0重导向 <、>
- 运行命令
$-

1
2
|
set -x # 启用命令跟踪
set +x # 禁用命令跟踪
|

字符串
1
2
3
4
5
6
7
8
9
10
11
12
|
str=abcdefg
${#str} # 返回字符串长度
4
# 字符串以0开始
# 字符串截取
${str:0:5} # 从0开始,截取5个
${str:5:5} # 从第六个开始,截取5个
${str::5} # 从0开始,截取5个
${str:0-6:5} # 从倒数第6开始,向后截取5个
${str: -4} # 字符串最后四个
|
printf

算术运算:$[],$(()),(())
bash 只支持整数,不支持小数
let var=expression
var=$[expression]
var=$((expression))
((var=expression))
declare -i var=number
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
i=123;j=456;
k=i+j;echo $k
i+j
let k=i+j;echo $k
579
expr 10+20
10+20
expr 10 + 20
30
expr 10 \* 20 # *需要转义
200
let num1+=1
((num1+=1))
|
expr

bc:除法小数实现
1
2
3
4
5
|
-l # 实现小数数学运算
-q # 静默
echo "scale=3;20/3"|bc
echo "20/3"|bc -l
|
随机变量
^:异或
同为假
异为真
$()
字符串操作

默认值相关

expr

read
1
2
3
4
5
6
|
read -p "请输入登录用户名: " user
# 限制字符数
read -n 6 -p "sss: " aaa
# 时长限制
read -t 5 -p "等待5秒后自动退出! " second
-d 'q' # 结束符设定
|
|:管道通常会创建子 Shell,因此在管道中定义的变量在当前 Shell 中不可见。
1
2
3
4
5
6
7
8
9
10
11
|
read i j < test.txt ; echo $i $j
1 2
echo 1 2 | read x y ; echo $x $y
无输出
echo 1 2 | ( read x y ; echo $x $y )
1 2
echo 1 2 | { read x y ; echo $x $y; }
1 2
|
条件测试命令
判断某需求是否满足
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
test xxxx
[ xxxxx ]
[[ xxxxx ]] # 判断字符串是否匹配;==(通配符);=~(正则)
# 状态码
0 为true
1 为false
# -a 和 -o 需要使用测试命令进行,[[ ]] 不支持
[ EXPRESSION1 -a EXPRESSION2 ] # and
[ EXPRESSION1 -o EXPRESSION2 ] # or
[ ! EXPRESSION1 ] # 取反
|
文件判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
-a FILE # 判断文件是否存在
-e FILE # 判断文件是否存在
-s FILE # 判断文件是否存在且不为空
-r FILE # 判断文件当前用户是否可读
-w FILE # 判断文件当前用户是否可写
-x FILE # 判断文件当前用户是否可执行
-O FILE # 判断文件当前用户是否为所属人
-G FILE # 判断文件当前用户是否为所属组
-k FILE # 判断文件是否有sticky位
-u FILE # 判断文件是否有SUID位
-b FILE # 判断文件是否为块设备
-c FILE # 判断文件是否字符设备
-d FILE # 判断文件是否为目录
-f FILE # 判断文件是否为普通文件
-p FILE # 判断文件是否为管道
-S FILE # 判断文件是否为套接字
-h FILE # 判断文件是否为软链接
-L FILE # 判断文件是否为软链接
FILE1 -eq FILE2 # 判断文件1是否为新于文件2的硬链接
-t FD # 判断文件描述符是否指向一个终端;判断脚本的输入是否来自于用户的终端
FILE1 -nt FILE2 # 判断文件1是否新于文件2
FILE1 -ot FILE2 # 判断文件1是否旧于文件2
|
字符串判断
1
2
3
4
5
6
7
8
9
10
11
12
13
|
-z STRING # 空为真
-n STRING # 非空为真
STRING
STRING1 = STRING2
STRING1 != STRING2
==
!=
<=
>=
<
>
|
数学判断;$(())与(())
- $(())用于求值返回结果
- (())用于求值返回布尔结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# 用于整数的比较
-eq
-ne
-lt
-le
-gt
-ge
a=5
b=10
# $(())用于求值返回结果
# (())用于求值返回布尔结果
if (( a >= b )); then
echo "a 大于等于 b"
fi
# 可以嵌入在条件判断中
if (( $(($a + $b)) > 10 )); then
echo "a + b 大于 10"
fi
# 小数比较
a=5.5
b=10.2
# 使用 bc -l 比较小数
if (( $(echo "$a < $b" | bc -l) )); then
echo "$a 小于 $b"
fi
|
其他
test:IP
1
2
3
4
|
[[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
IP=$1
[[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] && echo $IP is valid || echo $IP is invalid
|
&&,|| 与组合使用
&& 和 || 可以组合使用,形成类似“if…else”的逻辑结构。可以用以下方式来表达“如果命令成功则执行 A,否则执行 B”:
1
2
3
4
5
|
command && echo "Success" || echo "Failure"
COMMAND1 && COMMAND2 # 1成功,2执行; 1失败,2不执行
COMMAND1 || COMMAND2 # 1成功,2不执行; 1失败,2执行
! COMMAND #非,取反
|

true,false;没有0,1
if…fi
1
2
3
4
5
6
7
8
9
|
if commands
then
xxxxxx
elif commands
then
xxxxxx
else
xxxxxx
fi
|
case…esac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
case $input in
case1)
xxxx
xxxx
;;
case2)
xxxx
xxxx
;;
case3)
xxxx
;;
*) # 都没匹配到;default
xxxx
;;
esac
|
1
2
3
4
5
6
7
8
9
10
11
12
|
read -p "Do you agree(yes/no)? " INPUT
case $INPUT in
[yY]|[Yy][Ee][Ss])
echo "You input is YES"
;;
[Nn]|[Nn][Oo])
echo "You input is NO"
;;
*)
echo "Input fales,please input yes or no!"
;;
esac
|
for…done;(())
双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格的变量操作.
1
2
3
4
|
for i in item1 item2 ... itemN
do
xxxx
done
|
1
2
3
4
5
6
|
for((i=1;i<=9;i++));do
for((j=1;j<=i;j++));do
printf "\E[1;$[RANDOM%7+31]m${i}x${j}=$[i*j]\E[0m\t"
done
printf "\n"
done
|
while…done
1
2
3
4
|
while condition
do
xxxx
done
|

: 是 Shell 中的一个内建命令,它也是一个始终返回成功状态的空操作符。
while read
1
2
3
4
|
while read line
do
循环体
done < /PATH/FROM/SOMEFILE
|
unitl
1
2
3
4
|
until condition
do
command
done
|
continue
break
shift
shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift

select


function;自定义函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
function func_name(){
}
func_name(){
}
function func_name{
}
# 调用,直接函数名
func_name
# 引入函数文件
source func_file
. func_file
# 返回值
return 0
return xxx
# 获取返回值
使用 $?
# 参数
func_name 1 2 3 4
用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量
# 本地变量
# 默认全是全局
# 使用local为本地变量;变量会被限定在函数作用域内,函数结束后就无法在外部访问它。
my_function() {
var1="Hello from function"
}
my_function
echo "$var1" # 输出: Hello from function
#***************************************#
my_function() {
local var1="Hello from function"
}
my_function
echo "$var1" # 输出为空,或者会提示未定义
|
环境函数
使子进程也可使用父进程定义的函数
1
2
|
export -f function_name
declare -xf function_name
|