Shell与脚本
shell是Linux操作系统的用户接口,我们经常需要编写脚本让操作系统自动执行一系列指令的需求,本文将简单介绍开发shell脚本的所需的语言特性。
shell脚本是指令序列,其指令可以直接在终端中执行。同样地,终端中的指令也可以写到脚本中。
脚本文件通常以.sh
作为后缀名,第一行以#!
开头指定执行脚本的程序:
#!/usr/bin/bash
以#!
开头的第一行被称为Hashbang或Shebang。 而#
是shell脚本中的行注释符。
通常有三种执行脚本的方式:
sh start.sh
: 在终端中创建一个sh子进程执行脚本, 执行者需要拥有脚本的读权限。
该方式实际上是将脚本路径作为参数传递给了sh
命令。source start.sh
: 在终端中执行脚本,相当于将脚本中的指令逐条复制到终端执行。
脚本中局部变量将保留在终端环境变量中, 脚本的pid和工作目录等环境也与终端一致。./start.sh
: 根据HashBang指定的程序,在子进程中执行脚本。
sh
命令有一些有用的选项帮助我们开发和调试脚本:
sh -n start.sh
:对脚本进行语法检查, 不实际执行脚本sh -x start.sh
: 把将要执行的命令输出到stderr便于进行调试
变量
shell中变量是弱类型的, 变量名只能包含字母、数字或下划线"_",首字符只能为字母。
shell主要面向文本处理而非数据计算,因此变量默认类型为字符串型。
A=abc
echo $A
变量在使用前无需声明,在为变量赋值时=
左右不能添加空格。
A = abc
会被shell解释为执行指令A
,参数为=
和abc
。
$
为变量标志符, echo $A
指令将显示变量A的内容abc
, 为了明确指定变量名也可以写作${A}
。
A=a
AB=ab
echo ${A}B
$(cmd)
可以把命令的输出作为返回值, 如:
PWD=$(pwd)
变量$PWD
存储了当前的工作目录路径。
在shell中可以直接书写字符串,但仍建议用单引号或双引号标识字符串。
在单引号标识的字符串中$
不被作为变量标识符, 而双引号则会将$
替换为变量内容。
A="abc"
echo '$A' # $A
echo "$A" # abc
字符串拼接不需要任何运算符,只需要将它们写在一起即可:
A="abc"
B="123"
echo "$A+$B" # abc+123
echo "$A$B" # abc123
echo "$Adef" # abcdef
全局变量
变量按照作用域可以分为局部变量和全局变量,上文示例中定义的变量都是局部变量, 作用域仅限执行脚本的进程。
子进程可以继承父进程的全局变量,export
指令用于定义全局变量:
export A=abc
整型变量
shell仅支持整型计算, declare
命令可以声明整型变量,let
指令用于算术运算:
declare -i a=1
let a=a+1
echo $a # 2
let a+=1
echo $a # 3
let
指令支持算术运算符包括:
+
:加法-
: 减法*
: 乘法/
: 除法**
: 乘方%
: 取余
let
指令也支持算术运算符对应的算术赋值运算符,如+=
。
数组
bash中可以使用圆括号定义数组,元素之间用空格分割,数组下标从1开始:
arr=(1 'a' "abc")
echo ${arr[1]}
也可以直接使用下标定义数组:
arr2[1]=1
arr2[2]=2
该方法同样可以用于修改已存在的数组。
特殊变量
shell中预定义了一些特殊变量,通过这些变量可以获得环境信息:
$$
: 执行脚本的进程ID(pid)$?
: 上一条命令的返回值$!
: 上一条后台指令的执行进程的ID
上述变量在交互式终端中同样有效。
还有一些变量可以获得执行脚本时传入的参数:
$0
: 脚本的文件名$1
~$n
: 传给脚本的第n个参数$#
: 传入参数的个数$@
: 参数列表$*
: 单个字符串形式的参数列表
流程控制
if
declare -i a=90
if [ $a -gt 80 ]; then
echo "A"
elif [ $a -lt 60 ]; then
echo "C"
else
echo "D"
fi
结束标志fi
即是if
反写, 我们还将在其它地方遇到bash的这种命名风格。
注意,[]
旁边的空格不可省略。
-lt
, -gt
用于进行整型的大小比较:
-eq
: 等于(equal)-ne
: 不等于(not equal)-gt
: 大于(greater)-ge
: 大于等于(greater-equal)-lt
: 小于(less)-le
: 小于等于(less-equal)
进行复合逻辑判断也很简单:
if [ $a -gt 60 -a ( ! $a -gt 90 -o $a eq 91 ) ]; then
echo "make no sense"
fi
!
: 非-a
: 且and-o
: 或-o
逻辑运算遵循短路计算原则。
<
, >
等运算符在[]
中只能用于字符串的比较, 而在[[]]
中<
, >
可以用于整型和字符串的大小比较, 也可以使用&&
和||
来书写逻辑表达式。
if的条件判断不一定使用[]
或[[]]
表达式,它可以是任何一个命令。命令的返回值为0则if判断为真, 非0判断为假。
[]
和[[]]
转义表达式也可以像普通指令一样执行,判断为真则返回0,假则返回非0值。
[ 2 -gt 1 -a 3 -lt 4 ] && echo 'ok'
除此之外,if还可以进行更多种类的条件判断:
判断字符串相等
if [ ${NAME} = 'tmp' ]; then
echo "name is tmp"
fi
判断文件是否存在
if [ -e tmp ]; then
echo "tmp exists"
fi
判断tmp
是否存在,tmp
可以是目录或文件。
判断是否为普通文件
if [ -f tmp ]; then
echo "file tmp exists"
fi
判断tmp
是否为文件,tmp
不能是目录。
判断是否为目录
if [ -d tmp ]; then
echo "directory tmp exists"
fi
判断是否具有执行权限
if [ -x tmp ]; then
echo "tmp is executable"
fi
不判断文件是否可执行,只判断是否拥有x
权限。 因此,tmp为有x权限的目录时也会判断为真。
类似的还有,-w
判断是否拥有写入权限, -r
判断是否拥有读取权限。
判断是否为空文件
if [ -s tmp ]; then
echo "file is not empty"
fi
case
case类似于其它语言中的switch语句:
case ${NAME} in
'a')
echo "name is a"
;;
'b')
echo "name is b"
;;
*)
echo "other names"
;;
esac
从第一个匹配的标签开始执行, 两个标签之间必须有;;
,*)
是其它标签都不匹配时的默认标签。
for
for循环可以遍历一个序列:
for i in $(seq 1 10); do
echo $i
done
# echo: 1 2 3 ... 10
一些命令的输出也可以作为序列:
for i in $(ls); do
echo $i
done
遍历所有参数:
for arg in "$@"; do
echo $arg
done
另一种形式的for循环:
for (( i=0; i<100; i++)); do
echo $i
done
while
declare -i i=0
while [ $i -lt 10 ]; do
echo $i
i=$i+1
done
while(true)
这样的死循环也很容易:
declare -i i=0
while ; do
echo $i
[ ! $i -lt 10 ] && break
i=$i+1
done
函数
shell提供了定义函数的功能, 函数就像是脚本中的子脚本:
range() {
for (( i=0; i<${1}; i++)); do
echo $i
done
return ${1}
}
range 100
函数同样使用位置参数$1
~$n
来访问参数,$0
为函数的名称, $@
, $#
等变量的含义不变。
进程间通信
管道
管道用于将上一条指令的输出作为下一条指令的输入:
ls | grep ".zip"
xargs
有一些指令不支持使用管道传递参数,因此需要xargs
命令
find ~ | xargs ls
xargs会以空格为分隔符将输入分隔为参数,然后将参数传给ls。
重定向
重定向用于将命令的输入输出从标准流重定向到文件。标准流包括:
- stdin: 标准输入流,文件描述符为0
- stdout: 标准输出流,文件描述符1
- stderr: 标准错误流,文件描述符2
输出到文件,覆盖原有内容:
echo "hello" > 1.txt
输出到文件, 追加到文件尾:
echo "hello" >> 1.txt
从文件输入:
wc -l < 1.txt
重定向标准错误输出流:
cmd 2> 2.txt
将标准错误输出追加到文件:
cmd 2>> 2.txt
将标准错误和标准输出一同重定向到文件:
cmd > 1.log 2>&1
2>&1
是将stderr重定向到stdout。
后台执行
shell可以执行一行指令后立即返回, 返回后可以通过$?
变量获得执行进程的ID:
$ sleep 10 &
[1] 79403
$ echo $!
79403
Shell与脚本的更多相关文章
- shell及脚本4——shell script
一.格式 1.1 开头 必须以 "# !/bin/bash" 开头,告诉系统这是一个bash shell脚本.注意#与!中间有空格. 二.语法 2.1 数值运算 可以用decla ...
- 【Telnet】使用Telnet协议连接到远程Shell执行脚本
介绍 本文介绍如何通过Telnet协议连接到远程Shell,执行脚本,并获取执行结果: 相关文章: <[Jsch]使用SSH协议连接到远程Shell执行脚本>http://www.cnbl ...
- shell自动计算脚本
shell自动计算脚本 #!/bin/bash echo $(($)) [root@bogon ~]# sh b.sh 123+123246 let用户声明这个操作是要计算,后者的效率更高 (expr ...
- Shell菜单脚本
今天在这儿给大家分享一个我简单编写的Shell菜单脚本,傻瓜式的人机交互,人人都可以操作linux. #!/bin/sh #Shell菜单演示 function menu () { cat <& ...
- shell常见脚本30例
shell常见脚本30例 author:headsen chen 2017-10-19 10:12:12 本文原素材出自网上,特此申明.有些地方加入我自己的改动 常见的30例shell脚本 1.用 ...
- shell常用脚本
shell常用脚本 author:headsen chen 2017-10-17 15:36:17 个人原创,转载请注明,否则依法追究法律责任 1,vim name.grep.sh 2,cat ...
- 一篇关于Maven项目的jar包Shell启动脚本
使用Maven作为项目jar包依赖的管理,常常会遇到命令行启动,笔者也是哥菜鸟,在做微服务,以及服务器端开发的过程中,常常会遇到项目的启动需要使用main方法,笔者潜心的研究了很多博客,发现大多写的都 ...
- Linux shell编写脚本部署pxe网络装机
Linux shell编写脚本部署pxe网络装机 人工安装配置,Linux PXE无人值守网络装机 https://www.cnblogs.com/yuzly/p/10582254.html 脚本实 ...
- 使用shell解析脚本依赖关系,并自动补数
将脚本依赖关系放到表中 使用shell解析脚本依赖关系,递归的计算各个脚本. #!/bin/bash # dm 补数 basepath=$(cd ``; pwd) cd $basepath sourc ...
- shell监控脚本
序言: 前几天一好友问我服务器监控怎么做?你们公司的监控是怎么做的?有什么开源的监控软件推荐?常见的开源的监控软件当然首先推荐ZABBIX,分布式够强大,而且很多公司都在用,我问他具体什么需求,能监控 ...
随机推荐
- 【Sql】mySQL在windows环境启动
SQL的不同版本在Windows环境启动配置方法不同,此处仅介绍 5.7.20的配置方法: 1.登录mysql官网下载windows环境下的工具压缩包 http://dev.mysql.com/dow ...
- 如何在SecureCRT中给linux上传和下载文件 安装redis
首先建立文件 /download sz和rz命令无法用.则用以下1.和2.3步骤 需要上传或者下载,需要使用rz和sz命令.如果linux上没有这两个命令工具,则需要先安装.可以使用yum安装.运 ...
- php 使用 ffmpeg 转换视频,截图,并生成缩略图
http://blog.csdn.net/toss156/article/details/7003059 把ffmpeg 和 生成缩略图整合了一下. include("ImageResiz ...
- 基于Vue的页面切换左右滑动效果
HTML文本页面: <template> <div id="app> <transition :name="direction" mode= ...
- 邓_html_图片轮播
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Django权限机制的实现
Django权限机制的实现 1. Django权限机制概述 权限机制能够约束用户行为,控制页面的显示内容,也能使API更加安全和灵活:用好权限机制,能让系统更加强大和健壮.因此,基于Django的开发 ...
- 让自己写的项目支持Cocoapods管理
学会使用别人的 Pods 依赖库以后, 你一定对创建自己的依赖库很有兴趣吧,现在我们一起来制作自己的Pods依赖库. 1.创建自己的 github 仓库 上图中标识出了6处地方 Repository ...
- SpringMvc4.x--@ControllerAdvice注解
通过@ControllerAdvice.我们可以将对于控制器的全局配置放置在同一个位置,注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler,@InitBind ...
- 使用Python查询JMX
一.介绍 我们知道 java 项目中的 JMX 接口信息是十分有用的,我们可以提取这些信息来分析或告警.但是 JMX 的 API 只在 java 中实现,因此,找到一个 Python 代码调用 Jav ...
- Django_生产环境静态文件配置
需求: 当Django项目运行在线上的时候,需要关闭debug模式,那么Django设置中,静态文件路径配置将会失效,如何解决这个问题? 问题原因: Django默认关闭debug模式,Django错 ...