shell脚本从入门到精通(初级)之入门篇
写在开头
本文是阅读《Linux命令行与shell脚本编程大全》时的一些笔记,主要是shell脚本的一些基本语法,
还有很多细节和高级内容没有写到。
笔者也是shell script菜鸟,如有不当欢迎指正。
shell脚本从入门到精通(初级)之入门篇
shell脚本从入门到精通(中级)之提高篇
目录:
一、变量
二、数学计算
三、逻辑控制
四、输入
五、输出
六、函数
七、控制脚本
一、变量
1. 环境变量
#!/bin/bash
# 环境变量
echo "User Info:"
echo "user: $USER"
echo "UID : $EUID"
echo "home: $HOME"
echo “$HOSTNAME”
2. 用户变量
变量命名规则:
- 由字母、数字和下划线组成
- 大小写敏感
#!/bin/bash
# 用户变量
var1=100
var2=hello
var3="hello world"
echo "$var1 $var2 $var3"
3. 特殊变量
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |
#!/bin/bash
echo "Total Number of Parameters : $#"
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "PID $$"
echo "$?"
$@ 与 $* 的区别
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。
但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
#!/bin/bash
echo ‘$@:’
for i in $@;do
echo $i
done
echo ‘"$@:"’
for i in "$@";do
echo $i
done
echo ‘$*:’
for i in $*;do
echo $i
done
echo ‘"$*:"’
for i in "$*";do
echo $i
done
结果:
$@:
1
2
3
"$*":
1
2
3
$@:
1
2
3
"$*":
1 2 3
4. ``与$()
把命令的执行结果赋给变量的两种方式
#!/bin/bash
time=`date +%y%m%d`
time=$(date +%y%m%d)
二、数学计算
1. expr
#!/bin/bash
# 注意变量和=之间不能有空格,expr 和 = 之间要有一个空格
var= expr 1 + 2
echo $var
expr 极难用,一般不用
2. [] 与 (())
#!/bin/bash
#
var=$[ 1 + 2 ]
var=$(( 3 + 4 ))
3. bc
上述两种只能计算整数,对于浮点数需要使用bc
在脚本中使用bc的格式:
variable=`echo "option; expression" |bc`
#!/bin/bash
var=`echo "scale=2;5/3" | bc`
echo $var
三、逻辑控制
1. if
1.1 if-then
格式:
if command
then
command
fi
例:
#!/bin/bash
if date
then
echo "command is succeed"
fi
1.2 if-then-else
格式:
if command
then
command
else
command
fi
例:
#!/bin/bash
# 查找系统中是否存在httpd用户
if grep httpd /etc/passwd
then
echo "httpd is exist"
else
echo "httpd not find"
fi
1.3 if嵌套
格式:
if command
then
command
elif command
command
else
command
fi
2. test
功能:
- 数值比较
- 字符串比较
- 文件比较
格式:
test condition
或
[ command ] -- 更常用
2.1 数值比较
比较 | 描述 |
---|---|
-eq | 等于 |
-ge | 大于等于 |
-gt | 大于 |
-le | 小于等于 |
-lt | 小于 |
-ne | 不等于 |
例:
#!/bin/bash
date
if [ $? -eq 0 ];then
echo "command is succeed"
fi
# 或
if test date;then
echo "command is succeed"
fi
2.2 字符串比较
比较 | 描述 | 例 |
---|---|---|
str1 = str2 | 字符串是否相同 | |
str1 != str2 | 字符串是否不同 | |
str1 < str2 | str1是否比str2小 | |
str1 > str2 | str1是否比str2大 | [ b \> a ] && echo "true" (注意>需要转义) |
-n str | 字符串长度非0为真 | [ -n "str" ] && echo "str is not null" |
-z str | 字符串长度为0为真 | [ -z "" ] && echo "str is null" |
2.3 文件比较
比较 | 描述 | 例 |
---|---|---|
-d file | 检查file是否存在并是一个目录 | [ -d /data ] && echo "exist" |
-f file | 检查file是否存在并是一个目录 | |
-e file | 检查file是否存在 | |
-r file | 检查file是否存在并可读 | |
-s file | 检查file是否存在并非空 | |
-w file | 检查file是否存在并可写 | |
-x file | 检查file是否存在并可执行 | |
-O file | 检查file是否存在并属当前用户所有 | |
-G file | 检查file是否存在并且默认组与当前用户相同 | |
file1 -nt file2 | file1是否比file2新 | |
file1 -ot file2 | file1是否比file2旧 |
2.4 复合条件
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
3. case
格式:
case variable in
pattern1 | pattern2) command1;;
pattern3) command2;;
*) default command;;
esca
例:
#!/bin/bash
read -p "input something: " var
case $var in
[0-9])
echo "number";;
[a-z])
echo "character";;
*)
echo "other";;
esac
4. for
4.1 bash中的for
格式:
for var in list
do
command
done
例1:查看服务状态
#!/bin/bash
for service in apache2 mysqld zabbix-server zabbix-agent
do
status=$(systemctl status mysql | awk '/Active/ {print $2,$3}')
echo $service $status
done
例2:使用通配符
#!/bin/bash
# 注意在$file上加“”,否则如果出现带空格的目录名,脚本会出错
for file in /tmp/*
do
if [ -d "$file" ]
then
echo "$file" is a directory
elif [ -f "$file" ]
then
echo "$file" is a file
fi
done
4.2 C 语言风格的for
例:
#!/bin/bash
for (( i=1; i<=10; i++ ))
do
echo $i
done
#!/bin/bash
# 单变量
for (( i=1; i<=10; i++ ))
do
echo $i
done
# 多变量
for (( i=1,j=10; i<=10; i++,j-- ))
do
echo $i $j
done
5. while
例:检测站点状态
#!/bin/bash
urls="
https://www.baidu.com
https://www.taobao.com
https://www.jd.com/abc
https://www.12306.cn/index/
192.168.1.111
"
for url in $urls;do
count=0
while [ $count -lt 3 ];do
STATUS=$(curl -I -m 10 -o /dev/null -s -w %{http_code} $url)
if [ $STATUS -eq 200 ];then
echo "$url OK"
break 1
fi
count=$(($count+1))
done
if [ $count -eq 3 ];then
echo "$url Error"
fi
done
6. until
#!/bin/bash
var=10
until [ $var -eq 0 ];do
var=$[$var-2]
echo $var
done
7. 控制循环
7.1 break
#!/bin/bash
# break 跳出当前循环
# break n 跳出n层循环
for (( i=0; i<10; i++ ));do
if [ $i -eq 5 ];then
break
fi
echo $i
done
7.2 continue
四、输入
1. 命令行参数
例1:
#!/bin/bash
echo $1+$2=$[$1+$2]
./add.sh 3 4
3+4=7
例2:shift
#!/bin/bash
# 把变量的位置向左移
while [ -n "$1" ];do
echo $1
shift
done
2.getopts
格式:getopts optstring variable
optstring: 选项字母,如果字母要求有参数就加一个:,要去掉错误消息的话可以在optstring前加一个:
variable:保存当前参数
#!/bin/bash
# getopts的用法
# opt 会保存输入的参数,如 r i
# OPTARG保存参数值
# 参数需要一个值就在参数后面加一个: 如i:
while getopts ri: opt
do
case "$opt" in
i) echo "install service $OPTARG";;
r) echo "remove all service";;
*) echo "Unknown option: $opt";;
esac
done
root@localhost:/# ./getopts.sh -i apache2
install service apache2
root@localhost:/# ./getopts.sh -r
remove all service
root@localhost:/# ./getopts.sh -a
./getopts.sh: illegal option -- a
Unknown option: ?
3. 获得用户输入 read
3.1 普通用法
#!/bin/bash
read name
echo $name
3.2 指定提示符
#!/bin/bash
read -p "Enter your name: " name
echo "Hello $name "
3.3 指定超时时间
#!/bin/bash
if read -t 5 -p "Enter your name: " name
then
echo "Hello $name"
else
echo "TIME OUT"
fi
3.4 隐藏数据
#!/bin/bash
read -s -p "Enter passwd: " passwd
echo "$passwd"
3.5 限制输入长度
#!/bin/bash
read -n1 -p "Do you want continue[Y/N]?" answer
echo
echo "$answer"
五、输出
显示脚本输出的方法:
- 在显示器上显示
- 将输出重定向到文件
描述符 | 缩写 | 描述 |
---|---|---|
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准错误 |
1. 在脚本中重定向
1. 临时重定向
使用场景:在脚本中生成错误消息
#!/bin/bash
echo "This is an error message" >&2
echo "This is normal output"
默认情况下Linux 会将STDERR定向到STDOUT
$./error.sh
This is an error message
This is normal output
在执行脚本的时候重定向STDERR,ERR文本就会被重定向
$ ./error.sh 2> error.log
This is normal output
$ cat error.log
This is an error message
2. 永久重定向
用exec命令告诉shell在执行脚本期间重定向某个特定文件描述符
#!/bin/bash
exec 2>errout
echo "This is error"
exec 1>testout
echo "testout"
echo "testout to errout" >&2
$ ./test.sh
This is error
$ cat errout
testout to errout
$ cat testout
testout
2. 记录消息
tee : 将输出一边发送到显示器一边发送到日志文件
tee 默认会覆盖原来的文件,可以使用-a追加
$ date | tee -a date.txt
Fri Nov 23 11:03:15 CST 2018
$ cat date.txt
Fri Nov 23 11:03:07 CST 2018
Fri Nov 23 11:03:15 CST 2018
六、函数
1.基本函数
#!/bin/bash
# 定义方式1
function foo {
echo "This is a func"
}
# 定义方式2
bar() {
echo "This is another func"
}
# 函数的调用
foo
bar
$ ./func.sh
This is a func
This is another func
2.返回值
- 默认退出状态码
#!/bin/bash
function foo {
echo "This is a func"
}
foo
echo "Exit status is $?"
- 使用return命令
#!/bin/bash
function foo {
echo "Hello world"
return 2
}
foo
echo "Exit status is $?"
./func.sh
Hello world
Exit status is 2
- 使用函数输出
#!/bin/bash
function foo {
echo "Hello world"
}
foo
# 把函数的输出赋值给变量
result=`foo`
echo "Exit status is $result"
$./func.sh
Hello world
Exit status is Hello world
3.变量
- 传参
#!/bin/bash
function status {
systemctl status $1
}
status sshd
- 局部变量与全局变量
#!/bin/bash
# 定义全局变量
hostname="web"
function foo {
str="hello"
# 使用 local 定义局部变量
local user="http"
# 可以在函数内使用全局变量
echo "$hostname"
echo "$user"
}
foo
# 在函数中定义的局部变量不能在全局使用
echo "$str $user"
- 数组变量
如果将数组变量作为函数参数,函数只会取数组变量的第一个值
#!/bin/bash
function foo {
arr=$1
echo "The received array is ${arr[*]}"
}
myarr=(1 2 3 4 5)
foo $myarr
解决方法
#!/bin/bash
function foo {
arr=$@
echo "The received array is ${arr[*]}"
}
myarr=(1 2 3 4 5)
# 将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。
foo ${myarr[*]}
七、控制脚本
1.处理信号
1.1查看Linux信号
kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
在Linux编程时会遇到的最常见的Linux系统信号
信 号 | 值 | 描 述 | 触发 |
---|---|---|---|
1 | SIGHUP | 挂起进程 | |
2 | SIGINT | 终止进程 | Ctrl + C |
3 | SIGQUIT | 停止进程 | |
9 | SIGKILL | 无条件终止进程 | |
15 | SIGTERM | 尽可能终止进程 | |
17 | SIGSTOP | 无条件停止进程,但不是终止进程 | |
18 | SIGTSTP | 停止或暂停进程,但不终止进程 | Ctrl+Z |
19 | SIGCONT | 继续运行停止的进程 |
1.2 捕捉信号
格式:trap command signals
例
#!/bin/bash
trap "echo 'You Enter Ctrl + C'" SIGINT
for (( i=0; i<10; i++ ));do
echo $i
sleep 1
done
# ./signal.sh
0
1
^CYou Enter Ctrl + C
2
^CYou Enter Ctrl + C
2.脚本执行
- 脚本执行
bash file.sh
或
chmod +x file.sh
./file.sh - 后台运行脚本
./test.sh &
nohub ./test.sh &
附:退出状态
可以使用$?查看上一个命令的退出状态码
状态码 | 含义 |
---|---|
0 | 命令成功结束 |
1 | 通用未知错误 |
2 | 误用shell命令 |
126 | 命令不可执行 |
127 | 没有找到命令 |
128+x | Linux信号x的严重错误 |
130 | 命令通过Ctrl+C终止 |
255 | 退出状态码越界 |
shell脚本从入门到精通(初级)之入门篇的更多相关文章
- Promise入门到精通(初级篇)-附代码详细讲解
Promise入门到精通(初级篇)-附代码详细讲解 Promise,中文翻译为承诺,约定,契约,从字面意思来看,这应该是类似某种协议,规定了什么事件发生的条件和触发方法. Pr ...
- Android Studio2.0 教程从入门到精通Windows版 - 入门篇
http://www.open-open.com/lib/view/open1468121363300.html 本文转自:深度开源(open-open.com)原文标题:Android Studio ...
- 《shell脚本学习指南》学习笔记之入门
为什么要使用shell脚本? shell脚本能够轻易处理文件与目录之类的对象,而且是各UNIX系统之间经过POSIX标准化的通用的功能,因此Shell脚本只要“用心写”一次,即可应用到很多系统上,因此 ...
- linux shell 脚本攻略学习17--正则表达式入门
正则表达式(也称为“regex”或“regexp”)是一种用来描述文本模式的特殊语法.在 Linux 系统上,正则表达式通常被用来查找文本的模式,以及对文本流执行“搜索-替换”操作以及其它功能. 正则 ...
- Jmeter(十二) - 从入门到精通 - JMeter逻辑控制器 - 终篇(详解教程)
1.简介 Jmeter官网对逻辑控制器的解释是:“Logic Controllers determine the order in which Samplers are processed.”. 意思 ...
- 2、ASP.NET MVC入门到精通——Entity Framework入门
实体框架(Entity Framework)简介 简称EF 与ADO.NET关系 ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R ...
- 17、ASP.NET MVC入门到精通——Spring.net入门
Spring.NET环境准备 pring.NET 1.3.2下载地址:http://down.51cto.com/data/861700 下载后解压 Spring.NET-1.3.2.7z:这个里面有 ...
- Redis从入门到精通之一:序篇
Redis一直是我想好好研究的组件,但是之前受限于工作场景,没有真正意义的使用过.但是目前工作中,Redis作为主要的缓存组件来缓冲服务器的压力.所以,本序列主要结合实际工作中遇到的各种Redis的设 ...
- Android Studio2.0 教程从入门到精通Windows版 - 安装篇
详见:http://www.open-open.com/lib/view/open1468118887690.html
- raphael入门到精通---属性和事件篇
属性的使用 上一篇文章我们介绍了raphael如何生成基本的图形(元素),对于每个元素来讲,我们可以添加很多的元素(attr) 下面我就来简单的介绍下元素属性的使用(path元素属性我后面单独列出来介 ...
随机推荐
- 前端每日实战:45# 视频演示如何用纯 CSS 创作一个菱形 loader 动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/eKzjqK 可交互视频教程 此视频 ...
- 【leetcode】1037. Valid Boomerang
题目如下: A boomerang is a set of 3 points that are all distinct and not in a straight line. Given a lis ...
- JLRoutes笔记
1.在info.plist中添加 <key>CFBundleURLTypes</key> <array> <dict> <key>CFBun ...
- 状压DP常用操作
1. 判断一个数字x二进制下第i位是不是等于1. 方法:if ( ( ( 1 << ( i - 1 ) ) & x ) > 0) 将1左移i-1位,相当于制造了一个只有第i位 ...
- 【HDOJ6655】Just Repeat(贪心)
题意:A和B两个人玩游戏,分别有n和m张牌,A的第i张牌是a[i],B是b[i] 两人轮流出牌,如果一种编号的牌被其中一个人出了另一个人就不能出自己手中这个编号的牌 两人都按最优策略行动,问获胜者 思 ...
- [CSP-S模拟测试]:Simple(数学)
题目描述 对于给定正整数$n,m$,我们称正整数$c$为好的,当且仅当存在非负整数$x,y$,使得$n\times x+m\times y=c$. 现在给出多组数据,对于每组数据,给定$n,m,q$, ...
- [CSP-S模拟测试]:建设城市(city)(组合数学+容斥)
题目传送门(内部题8) 输入格式 一行三个整数$n,m,k$. 输出格式 一行一个整数表示答案.对$998244353$取模. 样例 样例输入 3 7 3 样例输出 数据范围与提示 对于10%的数据, ...
- 配置自己的CocoaPods库
序 默认安装的cocoapods确实很好用,可是毕竟自己会写一些库和修改一些第三方库来用.所幸cocoapods确实是一个神器.他可以定义自己的库来用. 如何安装Cocoapods,请参考这篇 从头来 ...
- 金山云无法ping通外网
解决方法:在网络安全组中放行ping端口.
- p5341 [TJOI2019]甲苯先生和大中锋的字符串
分析 TJOI白给题 建出sam,对于每个点如果它的子树siz和等于k 那么对于这个满足的点它有贡献的长度一定是一个连续区间 直接差分即可 代码 #include<bits/stdc++.h&g ...