shell

2019-08-12-Shell

Shell

第一个Shell

1
2
#!/bin/bash
echo "Hello World!"
1
2
3
4
5
bash -x file.sh        #单步执行  
/etc/motd && /etc/issue
printenv env export # 查看当前shell中的环境变量
set # 查看shell中的变量
unset # 撤销变量
选项 说明
-e 支持\转义
-n 输出不换行

变量

定义变量

1
2
3
4
your_name="anyue967",  # 变量名前不加$,不能有空格  

for file in `ls /etc` # 显示直接俄赋值/语句赋值
for file in $(ls /etc)
特殊符号 说明
() 重新开子shell中执行 $( ls;cd /etc/ )
{} 当前shell中执行${ ls;cd /etc/; }
“”
‘’
`` / $() 执行命令
[] 变量测试
# 注释
$ 引用变量
\ 转义符

使用变量

引用变量时, 变量名前要加$, 建议变量名外加{}, 一种习惯

1
2
3
for skill in Ada Coffe Action Java Shell; do
echo "I am good at ${skill}Script"
done

变量类型: 局部、环境、Shell变量三种

  • local 局部变量 在脚本或命令中定义, 仅在当前shell实例中有效, 其他shell启动的程序不能访问局部变量;
  • export 环境变量 作用范围:当前shell及子shell;
  • shell变量 shell变量是由shell程序设置的特殊变量, shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行;
  • 只读变量 readonly name 或 declare -r name readonly -p
  • 各个环境变量配置文件(source <==> .)
    • profile: 设定环境变量,运行命令/脚本
    • bashrc: 设定本地变量,定义命令别名

配置文件

1
2
登录shell:/etc/profile -->/etc/profile.d/*.sh -->~/.bash_profile -->~/.bashrc -->/etc/bashrc
非登录shell:~/.bashrc -->/etc/bashrc -->/etc/profile.d/*.sh
  • 位置变量

    符号 说明
    $1,$2,… 对应位置参数
    $0 脚本名称
    $* 传递所有参数,全部参数合为一个字符串
    $@ 传递所有参数,每个参数表现为独立字符串
    $# 参数个数
    $? 返回最后一条命令执行的状态
    $$ 当前进程PID
    $! 后台运行最后一个进程的PID
    set 清空所有位置变量
    shift n 移动参数,前n位参数被销毁
  • 关于()、(())、[]、[[]]、{}

  • 参考

    类型 说明
    () 用于多个命令组、命令替换cmd、初始化数组$(cmd)
    (()) 算数:整数扩展、运算符、重定义变量值、算数运算比较
    [[]] 支持数学运算,支持逻辑测试: `&&
    []/test 不支持数学运算,比较运算:== !=,逻辑测试使用: -a -o !
    {} 用于命令合集或者范围,mkdir -p /data/201{7,8}

字符串

字符串, 可以用'', 也可以用""

  • 单引号里的任何字符都会原样输出, 单引号字符串中的变量是无效的;

  • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行), 但可成对出现,作为字符串拼接使用

  • 双引号里可以有变量, 可以出现转义字符

  • 获取字串长度

1
2
string="abcd"
echo ${#string} # 4
  • 提取字符串
1
2
string="anyue967 is a good website"
echo ${string:1:4} # nyue
  • # ##表示去掉左边, #表示从左边删除到第一个指定的字符; ##表示从左边删除到最后一个指定的字符
  • % %%表示去掉右边, %表示从右边删除到第一个指定的字符; %%表示从右边删除到最后一个指定的字符
1
2
3
4
5
6
7
8
#!bin/bash
var="http://www.runoob.com/linux/linux-shell-variable.html"

s1=${var%%t*} # h
s2=${var%t*} # http://www.runoob.com/linux/linux-shell-variable.h
s3=${var%%.*} # http://www
s4=${var#*/} # /www.runoob.com/linux/linux-shell-variable.html
s5=${var##*/} # 空

数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小

1
2
3
4
5
6
7
8
9
10
11
12
定义: arrName=(value1 value2 ... n)

array_name=(
value0
value1
value2
)
array_name[0]=value0 # 引用数组
echo "数组元素: ${array_name[@]}"
echo "数组元素: ${array_name[*]}"

echo "数组元素个数为: ${#array_name[*]}"

注释

#开头单行注释

1
2
3
4
:<<EOF
comment...
comment...
EOF

read命令, 用于获取键盘输入信息

read [-option] [variable ...]

选项 说明
-p “提示信息”
-t 时间
-s 隐藏输入
-n 只接收一个输入字符就会执行
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
read -p "input a val:" a
read -p "input a val:" b

c=$(($a+$b)) # $((exp))
c=$[$a+$b] # $[exp]
let c=$a+$b # let exp
c=expr $a + $b # expr 算数表达式

echo "result=${r}"

传递参数

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
echo "参数个数:$#";
echo "进程号:$$";
echo "后台运行的最后一个进程号:$!";
echo "传递参数作为字串显示:$*";
echo "命令推出状态:$?";

Shell基本运算符

let 命令用于指定算术运算, 即let expretion

  • let var=$[exp] 算数表达式 $((exp))
  • echo $[$RANDOM%50]: 0-49之间随机数
    • COLOR=$[$RANDOM%7+31]; echo -e "\e[1;${COLOR}mcolor\e[0m"

declare

  • declare -i I=1 # 整型变量声明

算数运算, 用(())

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
#!/bin/bash
a=10
b=20

val=expr $a + $b
echo "a + b : $val"

val=expr $a - $b
echo "a - b : $val"

val=expr $a \* $b
echo "a * b : $val"

val=expr $b / $a
echo "b / a : $val"

val=expr $b % $a
echo "b % a : $val"

if [$a == $b ]; then
echo "a 等于 b"
fi
if [ $a != $b ]; then
echo "a 不等于 b"
fi

关系运算(-eq -ne -gt -lt -le)

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
#!/bin/bash
a=10
b=20

if [ $a -eq $b ]; then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]; then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]; then
echo "$a -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]; then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]; then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]; then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi

布尔运算(!= -a -o)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
a=10
b=20

if [ $a != $b ]; then
echo "$a != $b : a 不等于 b"
else
echo "$a == $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]; then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]; then
echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]; then
echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi

逻辑运算(&& || )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
a=10
b=20

if [[ $a -lt 100 && $b -gt 100 ]]; then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]; then
echo "返回 true"
else
echo "返回 false"
fi

文件测试(-r -w -x -f -d -s -e)

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
#!/bin/bash
file="/var/www/runoob/test.sh"

if [ -r $file ]; then
echo "文件可读"
else
echo "文件不可读"
fi
if [ -w $file ]; then
echo "文件可写"
else
echo "文件不可写"
fi
if [ -x $file ]; then
echo "文件可执行"
else
echo "文件不可执行"
fi
if [ -f $file ]; then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -d $file ]; then
echo "文件是个目录"
else
echo "文件不是个目录"
fi
if [ -s $file ]; then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file ]; then
echo "文件存在"
else
echo "文件不存在"
fi

字符串运算(= != -z -n)

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
#!/bin/bash
a="abc"
b="efg"

if [ $a = $b ]; then
echo "$a = $b : a 等于 b"
else
echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]; then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ -z $a ]; then
echo "-z $a : 字符串长度为 0"
else
echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]; then
echo "-n $a : 字符串长度不为 0"
else
echo "-n $a : 字符串长度为 0"
fi
if [ $a ]; then
echo "$a : 字符串不为空"
else
echo "$a : 字符串为空"
fi

Shell printf

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876

姓名 性别 体重kg
郭靖 男 66.12
杨过 男 48.65
郭芙 女 47.99

流程控制

if-elif-else-fi

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
#!/bin/bash
ratio = $(df -h |grep /dev/sda3 |awk '{print $5}' |cut -d "%" -f1)
if [ "$ratio" -ge 80 ]; then
echo "钉钉报警!"
fi
----------------------------------------------------
#!/bin/bash
ntpdate asia.pool.ntp.org &>/dev/null
date = $(date +%Y%m%d)
size = $(du -sh /var/lib/mysql)
if [ -d /tmp/dbbak ]; then
echo "Date: $date!" >/tmp/dbbak/dbinfo.txt
echo "Date: $size!" >>/tmp/dbbak/dbinfo.txt
cd /tmp/dbbak
tar -czf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
rm -rf /tmp/dbbak/dbinfo.txt
else
mkdir /tmp/dbbak
echo "Date: $date!" >/tmp/dbbak/dbinfo.txt
echo "Date: $size!" >>/tmp/dbbak/dbinfo.txt
fi
-----------------------------------------------------
#!/bin/bash
port = `nmap -sT 192.168.137.129 |grep tcp |grep http |awk '{print $2}'`
if [ "$port" == "open"]; then
echo "$(date) httpd is ok!" >>/tmp/autostart-acc.log
else
/etc/init.d/httpd start &>/dev/null
echo "$(date) restart ok!" >>/tmp/autostart-acc.log
fi
-----------------------------------------------------
#!/bin/bash
read -t 30 -p "Input num1:" num1
read -t 30 -p "Input num2:" num2
if [ -n "$num1" -a -n "$num2" -a -n "$opt" ]; then
test1 = $(echo num1 |sed 's/[0-9]//g')
test2 = $(echo num2 |sed 's/[0-9]//g')
if [ -z "$test1" -a -z "$test2" ]; then
if [ "$opt" == '+' ]; then
value = $(( $num1 + $num2 ))
elif [ "opt" == '-' ]; then
value = $(( $num1 - $num2 ))
elif [ "opt" == '*' ]; then
value = $(( $num1 * $num2 ))
elif [ "opt" == '/' ]; then
value = $(( $num1 / $num2 ))
else
echo "Please enter a valid symbol"
exit 10
fi
else
echo "Please input content"
exit 12
fi

for-do-done

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
57
58
59
60
61
62
63
64
65
66
67
68
#!/bin/bash
cd /root/tar
ls *.tar.gz >tar.log
ls *.tgz >>tar.log &>/dev/null
line = $(cat tar.log |wc -l)
for i in $line
do
tar -xzvf $i -C /root/tar
done
rm -rf tar.log

for (( i=1; i<"$line"; i++))
do
num = $(cat tar.log |awk 'NR=='$i' {print $1}')
tar -xzvf $num -C /root/tar
done
rm -rf tar.log
---------------------------------------------------------
#!/bin/bash
grep "<\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\>" /root/ip.txt >/root/iptest_1.txt
grep "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$" /root/ip.txt >/root/iptest_1.txt
line = $(wc -l /root/iptest_1.txt awk '{print $1}')
echo "" >/root/iptest.txt
for (( i=1; i<=$line; i++))
do
cat /root/iptest_1.txt |awk 'NR=='$i' {print}' >/root/iptest_2.txt
a = $(cat /root/iptest_2.txt |cut -d '.' -f1)
b = $(cat /root/iptest_2.txt |cut -d '.' -f2)
c = $(cat /root/iptest_2.txt |cut -d '.' -f3)
d = $(cat /root/iptest_2.txt |cut -d '.' -f4)
if [ "$a" -lt 1 -o "$a" -gt 255 ]; then
continue
fi
if [ "$b" -lt 0 -o "$b" -gt 255 ]; then
continue
fi
if [ "$c" -lt 0 -o "$c" -gt 255 ]; then
continue
fi
if [ "$d" -lt 0 -o "$d" -gt 255 ]; then
continue
fi
cat /root/iptest_2.txt >>/root/iptest.txt
done
rm -rf /root/iptest_1.txt
---------------------------------------------------------
#!/bin/bash
read -t 30 -p "Please input users name:" NAME
read -t 30 -p "Please input the number of users:" NUM
read -t 30 -p "Please input the password of users name:" PASS
if [ ! -z "$NAME" -a ! -z "$NUM" -a ! -z "$PASS"]; then
TMP = $(echo $NUM |sed 's/[0-9]//g')
if [ -z "$TMP" ]; then
for(( i=1; i<$NUM; i=i+1))
do
/usr/sbin/useradd $NAME$i &>/dev/null
echo $PASS |/usr/bin/passwd --stdin $NAME$i &>/dev/null
chage -d 0 $NAME$i &>/dev/null
done
fi
fi
---------------------------------------------------------
#!/bin/bash
user = $(cat /etc/passwd |grep "/bin/bash" |grep -v "root" |cut -d ":" -f1)
for i in $user
do
userdel -r $i
done

while-do-done

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
i = 1
s = 0
while [ $i -le 100 ]
do
s = $(( $s + $i ))
i = $(( $i + $1 ))
done
echo "The sum is: $s"

while while true for(( ; ; ))
do do
done done

case-in-esac

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
1) echo '你选择了 2'
;;
1) echo '你选择了 3'
;;
1) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac

关于 breakcontinue

  • break命令允许跳出所有循环(终止执行后面的所有循环)
  • continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环
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
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done

输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束
------------------------------------------------
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字: "
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done

Shell function

定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum$anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"


funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

shell
https://anyu967.github.io/posts/4592b2fd.html
作者
anyu967
发布于
2019年8月12日
许可协议