shell简明教程
shell的格式
shell可以在直接在命令行下输入,也可以保存成shell脚本文件运行。当命令简单并且不需要重复使用,在命令行输入直接执行即可,否则就写成脚本。shell脚本默认文件扩展名为.sh
。在shell脚本中,写入的内容,会默认当成一条命令来执行。
例如:
#!/bin/bash
echo 'hello world'
- 第1行 指定shell脚本的解释器
- 第2行 执行echo命令
将上面的代码存为test.sh,并将可执行权限赋予它chmod +x test.sh
,执行./test.sh
运行脚本。
上面的脚本将会输出:
hello world
这和在命令行或者终端模拟器下输入echo 'hello world'
并按下回车得到的结果是一样的
注释
和所有的编程语言一样,shell也有注释,在shell中,#号和它后面的内容来表示一个注释:
# Print a message
echo "I'm a shell script."
输出内容
echo命令用于向输出流输出内容,例如:
echo "hello world"
echo输出控制字符
echo -e "KEY\tVALUE\nluoye\t30"
输出
KEY VALUE
luoye 30
用printf命令格式化输出
printf "My name is %s,I'm %d years old." luoyesiqiu 20
输出
My name is luoyesiqiu,I'm 20 years old.
输入内容
read用于输入一条内容:
read input
echo $input
上面的代码中,read命令从输入流读取一个值并赋予input,然后将input的内容打印出来
1. 变量
1.1 定义变量和赋值
变量的命名规则和C语言差不多,支持英文字母和下划线。shell中变量名前不需要声明类型,"="号两边不能有空格,例如:
var1='hello'
var2=90
1.2 读取变量
$后接变量名意为读取一个变量的值,例如:
var="hello"
echo $var
也可以用${var}
方式访问到变量值,例如:
var="hello"
echo ${var}
访问变量的时候
$var
和${var}
是等效的,推荐后者来访问一个变量
1.3 变量作用域
1.3.1 全局变量
没有任何命令修饰的变量是一个全局变量,全局变量在同一个shell会话中都是有效的。
function func(){
a=90
}
func
echo $a
输出:
90
$ a=90
$ echo ${a}
$ bash
$ echo ${a}
输出:
90
空值
1.3.2 局部变量
local命令用于声明一个局部变量
function func(){
local a=90
}
func
echo $a
输出:
空值
1.3.3 环境变量
用export命令修饰的变量称为环境变量,在父shell会话中声明一个环境变量,子shell中都可以访问
$ export path="/system/bin"
$ bash #创建一个新的shell会话
$ echo ${path}
1.3.4 特殊变量
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n(n≥1) | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2 |
$# | 传递给脚本或函数的参数个数 |
$* | 传递给脚本或函数的所有参数 |
$@ | 传递给脚本或函数的所有参数 |
$? | 上个命令的退出状态,或函数的返回值 |
$$ | 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID |
1.3.5 $*和$@的区别
- $*得到所有参数被当成字符串
- $@得到所有参数都会被当成独立的参数
#!/bin/bash
for val in "$*"
do
echo "\$@ : ${val}"
done
for val in "$@"
do
echo "\$* : ${val}"
done
假如将上面的代码存为test.sh
,运行./test.sh 1 2 3
将输出:
$@ : 1 2 3
$* : 1
$* : 2
$* : 3
2. 获取一条命令的执行结果
2.1 用 ` 将一条命令包裹起来
` 这个符号,在键盘上的位置是在Esc键的下方
ret=`pwd`
echo ${ret}
在 ` 包裹起来的命令中,也可以访问到变量
path='/'
ret=`ls -l ${path}`
echo ${ret}
2.2 以$(command)这种方式执行命令
ret=$(pwd)
echo ${ret}
用$(command)这种方式也可以访问到变量
path='/'
ret=$(ls -l ${path})
echo ${ret}
上面的例子中,如果想打印命令结果中的换行符,则:
path='/'
ret=$(ls -l ${path})
echo "${ret}"
$(command)方式来执行命令更加直观,但是要注意,$(command) 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中都可使用
3. 字符串
shell有三种方式可以表示字符串
3.1 字符串的表示
(1)变量名后直接跟上字符
str=hello
echo ${str}
输出:
hello
这种方式的字符串遇到空格就会被终止
(2)单引号
str=hello
echo '${str}'
输出:
${str}
单引号里的内容是字符串原始的样子,不存在转义
(3)双引号
str=shell
echo "${str}:\"hello wolrd\""
输出:
shell:"hello world"
双引号中可以访问变量和转义
3.2 获取字符串的长度
str="hello"
echo ${#str}
输出:
5
3.3 字符串拼接
两个变量放在一起访问就可以拼接
a='hello'
b='world'
c=${a}${b}
echo ${c}
输出:
helloworld
也可以这样
echo 'hello'"world"
3.4 字符串截取
(1) 从左边开始截取字符串,格式:${string: start :length}
,length可省略,省略时,是截取到字符串末尾
msg="hello world"
echo ${msg: 6: 5}
输出:
world
(2) 在指定位置截取字符
- 截取chars后面的字符:
${string#*chars}
其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),是通配符的一种,表示任意长度的字符串。chars连起来使用的意思是:忽略左边的所有字符,直到遇见 chars(chars 不会被截取)。
截取最后一次出现chars的位置后面的内容:
${string##*chars}
使用 % 截取左边字符
使用%号可以截取指定字符(或者子字符串)左边的所有字符,具体格式如下:
${string%chars*}
请注意 * 的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以 * 应该位于chars的右侧。其他方面%和#的用法相同
4. 运算符和流程控制
4.1 基本运算
运算符 | 作用 |
---|---|
+ | 加(需要结合expr命令使用) |
- | 减(需要结合expr命令使用) |
* | 乘(需要结合expr命令使用) |
/ | 除(需要结合expr命令使用) |
% | 求余(需要结合expr命令使用) |
= | 赋值 |
== | 判断数值是否相等,需要结合[] 使用 |
!= | 判断数值是否不相等,需要结合[] 使用 |
a=8
b=4
echo "a=$a,b=$b"
var=`expr ${a} + ${b}`
echo "加法结果:${var}"
var=`expr ${a} - ${b}`
echo "减法结果:${var}"
# 注意:乘号需要转义
var=`expr ${a} \* ${b}`
echo "乘法结果:${var}"
var=`expr ${a} / ${b}`
echo "除法结果:${var}"
var=`expr ${a} % ${b}`
echo "求余结果:${var}"
var=$[${a} == ${b}]
echo "是否相等:${var}"
var=$[${a} != ${b}]
echo "是否不相等:${var}"
输出:
a=8,b=4
加法结果:12
减法结果:4
乘法结果:32
除法结果:2
求余结果:0
是否相等:0
是否不相等:1
上面的例子中,调用expr命令和使用[]
,得到表达式的值,并将它们输出
请注意表达式两边的空格,shell中表达式两边要有空格
4.2 关系运算
运算符 | 作用 |
---|---|
-eq | 全称:Equal,判断两个数是否相等 |
-ne | 全称:Not equal,判断两个数是否不相等 |
-gt | 全称:Greater than,判断前面那个数是否大于后面那个数 |
-lt | 全称:Less than,判断前面那个数是否小于后面那个数 |
-ge | 全称:Greater equal,判断前面那个数是否大于等于后面那个数 |
-le | 全称:Less than,判断前面那个数是否小于等于后面那个数 |
4.3 布尔运算
运算符 | 作用 |
---|---|
! | 非运算 |
-o | 或运算 |
-a | 并运算 |
4.4 逻辑运算
运算符 | 作用 |
---|---|
&& | 逻辑并 |
|| |
逻辑或 |
- 用
&&
连接起来的两个命令,前面的执行失败就不执行后面的命令
cd /bin && ls /bin
其实和C语言中的是差不多的,只要前面的条件不满足,后面那个就不用去执行它了
- 用
||
连接起来的两个命令,前面的执行失败才会执行后面的命令
cd /bin || ls /bin
在这里顺便说一下;
这个运算符,这个运算符用于连接多个语句,使多个语句能够在同一行。用;
连接起来的语句,不管前面的执行成不成功,都会执行后面的
mkdir luoye;cd luoye;pwd
4.5 文件判断
运算符 | 作用 |
---|---|
-e | 判断对象是否存在 |
-d | 判断对象是否存在,并且为目录 |
-f | 判断对象是否存在,并且为常规文件 |
-L | 判断对象是否存在,并且为符号链接 |
-h | 判断对象是否存在,并且为软链接 |
-s | 判断对象是否存在,并且长度不为0 |
-r | 判断对象是否存在,并且可读 |
-w | 判断对象是否存在,并且可写 |
-x | 判断对象是否存在,并且可执行 |
-O | 判断对象是否存在,并且属于当前用户 |
-G | 判断对象是否存在,并且属于当前用户组 |
-nt | 判断file1是否比file2新 |
-ot | 判断file1是否比file2旧 |
4.6 流程控制语句
(1) if语句
if语句格式如下:
if <condition>
then
#do something
elif <condition>
then
#do something
else
#do something
fi
如果想把then和if放同一行
if <condition> ; then
#do something
elif <condition> ; then
#do something
else
#do something
fi
其中elif和else可以省略
例子:
read file
if [ -f ${file} ] ; then
echo 'This is normal file.'
elif [ -d ${file} ] ; then
echo 'This is dir'
elif [ -c ${file} -o -b ${file} ] ; then
echo 'This is device file.'
else
echo 'This is unknown file.'
fi
逻辑判断也可以用test命令,它和[]
的作用是一样的
#!/bin/bash
a=4
b=4
if test $[a+1] -eq $[b+2]
then
echo "表达式结果相等"
else
echo "表达式结果不相等"
fi
输出:
表达式结果不相等
(2) for 语句
if语句格式如下:
for <var> in [list]
do
# do something
done
例子:
read input
for val in ${input} ; do
echo "val:${val}"
done
输入:
1 2 3 4 5
输出:
val:1
val:2
val:3
val:4
val:5
(3) while 语句
while <condition>
do
#do something
done
例子:
a=1
sum=0
while [ ${a} -le 100 ] ;do
sum=`expr ${sum} + ${a}`
a=`expr ${a} + 1`
done
echo ${sum}
输出:
5050
5. 数组
5.1 定义和基本用法
shell中也有数组,数组的格式是用英文小括号元素包裹起来,元素与元素之前用若干个分割符隔开(空格,制表符,换行符),这个分割符定义在IFS
变量中,我们可以通过设置IFS变量自定义分隔符。来看看如何定义一个数组:
array=(1 2 3 4 5 'hello')
也可以定义一个空数组
array=()
访问和修改数组元素的格式如下:
array[index]=value
和大多数编程语言一样,shell的数组索引也是从0开始的,假如想要分别修改数组的第一个和第二个元素为88和77:
array[0]=88
array[1]=77
上面的代码,如果array为空,88和77将被添加到数组中。
5.2 遍历
遍历数组太常见了,如果想对数组每个元素都进行特定的操作(访问,修改)就需要遍历。
在shell中,有两个方式可以得到数组的全部元素,${array_name[*]}
和${array_name[@]}
,有了这个知识,我们就遍历数组了
#!/bin/bash
array=("My favoriate number is" 65 22 )
idx=0
for elem in ${array[*]}
do
echo "Array element ${idx} is:${elem}"
idx=$(expr $idx + 1)
done
输出:
Array element 0 is:My
Array element 1 is:favoriate
Array element 2 is:number
Array element 3 is:is
Array element 4 is:65
Array element 5 is:22
在上面的代码中我们可能以为自己定义了一个字符串和两个数字在数组中,应该打印出一行字符串和两个数字。但是却不是这样的,只要有空白符,shell会把它们当成数组的分隔符,这些被隔开的部分就会被当成数组的元素。
6. 函数
- 用function关键字来定义一个函数
- 直接写一个函数名来调用一个无参数的函数
- 函数有参数,调用时,在函数名后面写上参数,多个参数用空格隔开
- 调用函数时传递参数,在函数体内部,通过 $n的形式来获取参数的值,例如:$1表示第1个参数,$2表示第2个参数...
6.1 函数的结构
function foo(){
# do something...
}
6.2 函数的用法示例
function foo(){
local name=$1
local age=$2
echo "My name is ${name},I'm ${age} years old."
}
foo "luoye" 26
输出:
My name is luoye,I'm 26 years old.
7. 重定向
重定向可以理解把一个东西传送到另个地方
重定向符 | 作用 |
---|---|
output > file | 将输出流重定向到文件 |
output >> file | 将输出流追加到文件末尾 |
input < file | 将文件的内容重定向到输入流 |
7.1 输出到文件
例子:
echo 'hello' > out.txt
echo 'world' >> out.txt
cat out.txt
输出:
hello
world
上面的例子,将hello
从输出流重定向文件,将world
追加到out.txt文件尾,最后用cat命令读取并打印out.txt的文件内容
重定向符还可以配合数字(0,1,2)使用
- 0 代表标准输入流
- 1 代表标准输出流,上面的例子没有指定数字,就是默认输出流
- 2 代表标准错误流
ls / 1> out.txt
cat out.txt
执行上面的命令,会将根目录下的文件名和目录名输出到out.txt
ls /luoye 2> out.txt
cat out.txt
执行上面的命令,会将执行ls /luoye
命令时的错误信息输出到out.txt
ls /;ls /luoye 2>&1
执行上面的代码,将错误流重定向到输出流,这种做法在某些场合是很有用的。
7.2 特殊文件
7.2.1 /dev/null
所有重定向到这个文件的内容都会消失,常常同于忽略错误输出。
ls /luoye 2> /dev/null
如果不存在/luoye这个目录或者文件,就没有什么提示
7.2.2 /dev/zero
这个文件会不断产出空的数据,该文件常被dd
命令使用
dd if=/dev/zero of=out.txt bs=1 count=16
从/dev/zero
输入,输出到out.txt
,生成一个大小为16字节的空文件
8. 管道
管道是Linux中的一种跨进程通信的机制,和重定向不同,管道用做进程与进程之间传送数据。做为Linux中默认的脚本语言,shell中也是可以使用管道的,在shell中,管道用|
表示
(1)使用管道进行数据筛选内容中包含root
的行
ls -l /|grep root
这个例子中,ls命令输出的内容传给了grep命令进行筛选
(2)也可以同时用多个管道
使用多个管道把数据筛选并统计
ls -l /|grep root|wc -l
这个例子中,ls命令输出的内容传给了grep命令进行筛选,然后转给wc命令统计行数。
为了更好的理解管道,写两个脚本来体验一下:
in.sh文件
#! /bin/bash
read msg
echo "Receive :${msg}"
out.sh文件
#! /bin/bash
echo 'hello'
在命令行中执行./out.sh |./in.sh
输出:
Receive :hello
符合我们预期,字符串hello从out.sh传送到了in.sh
9. 参考
- http://c.biancheng.net/shell/
- http://www.runoob.com/linux/linux-shell-process-control.html
- https://www.cnblogs.com/qlqwjy/p/8684630.html
- https://blog.51cto.com/skypegnu1/1543319
shell简明教程的更多相关文章
- CGIC简明教程(转摘)
CGIC简明教程 本系列的目的是演示如何使用C语言的CGI库“CGIC”完成Web开发的各种要求. ********************************* 基础知识 1 ...
- Vbs 脚本编程简明教程之一
—为什么要使用 Vbs ? 在 Windows 中,学习计算机操作也许很简单,但是很多计算机工作是重复性劳动,例如你每周也许需要对一些计算机文件进行复制.粘贴.改名.删除,也许你每天启动 计算机第一件 ...
- Gevent简明教程
Gevent简明教程 发表于 2015-11-28 | 分类于 技术| | 阅读次数 5159 前述 进程 线程 协程 异步 并发编程(不是并行)目前有四种方式:多进程.多线程.协程和异步. 多 ...
- python简明教程
Python简明教程 MachinePlay关注 0.7072018.09.26 01:49:43字数 2,805阅读 9,287 Python一小时快速入门 1.Python简介 pylogo. ...
- Environment Modules 简明教程
Environment Modules 简明教程 1. Modules 简介 在 Linux 超算平台上,通常会安装有不同版本的多种编译器和其他软件等,如常用的编译器有 intel 和 gnu,常用的 ...
- 2013 duilib入门简明教程 -- 第一个程序 Hello World(3)
小伙伴们有点迫不及待了么,来看一看Hello World吧: 新建一个空的win32项目,新建一个main.cpp文件,将以下代码复制进去: #include <windows.h> #i ...
- 2013 duilib入门简明教程 -- 部分bug (11)
一.WindowImplBase的bug 在第8个教程[2013 duilib入门简明教程 -- 完整的自绘标题栏(8)]中,可以发现窗口最大化之后有两个问题, 1.最大化按钮的样式 ...
- 2013 duilib入门简明教程 -- 部分bug 2 (14)
上一个教程中提到了ActiveX的Bug,即如果主窗口直接用变量生成,则关闭窗口时会产生崩溃 如果用new的方式生成,则不会崩溃,所以给出一个临时的快速解决方案,即主窗口 ...
- 2013 duilib入门简明教程 -- 自绘控件 (15)
在[2013 duilib入门简明教程 -- 复杂控件介绍 (13)]中虽然介绍了界面设计器上的所有控件,但是还有一些控件并没有被放到界面设计器上,还有一些常用控件duilib并没有提供(比如 ...
随机推荐
- AdminIII连接linux Postgresql过程中的几个小问题
1.postgresql.conf主配置文件中要配置postgresql绑定的IP,如果不设置,可能只绑定本地闭环地址:127.0.0.1,可以设定为0.0.0.0:就包括了一切IPv4地址 2.pg ...
- 推荐个Mac OSX下的Code Editor:Atom
首先只是当Editor用,不是整成IDE级. 先说几个大家耳熟能详的: 1.Sublime,Sublime在Mac下的安装并不完全,CLI启动需要自己ln个链接.还有一些其他原因,比如Packages ...
- 关于SpringMVC控制器的一点补充
首先复习一下之前控制器的写法:http://www.cnblogs.com/eco-just/p/7882016.html. 我们可以看到,之前的写法是这样的: @RequestMapping(&qu ...
- 浅谈编程语言中的新宠Python,你叫它如何不火?
论述 凡是对编程有所关注的朋友都已经知道,Python公布于1991年,即使出现的时间不是很遥远,但是在众多爱好者的贡献下已经发展到全民Python的地步. Python最近火起来的笼统原因:面向企业 ...
- mvc中路由的映射和实现IHttpHandler挂载
首先我们了解一下一般的方法 我们只需要在web.config配置文件中做映射处理即可. 第一种形式: <system.web> <urlMappings enabled=" ...
- Python_字符串简单加密解密
def crypt(source,key): from itertools import cycle result='' temp=cycle(key) for ch in source: resul ...
- 微信小程序-统一下单、微信支付(Java后台)
1.首先分享 微信统一下单接口: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 微信接口 签名 对比网址: https: ...
- MySQL 数据库 Query 的优化
理解MySQL的Query Optimizer MySQL Optimizer是一个专门负责优化SELECT 语句的优化器模块,它主要的功能就是通过计算分析系统中收集的各种统计信息,为客户端请求的Qu ...
- springboot中配置文件application.properties的理解
前言 Spring Boot使用"习惯优于配置"(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来.所以,我们要想把Sprin ...
- DropZone(文件上传插件)
1. html文件 dropzone的原理是模拟表单来上传文件,html中的元素有多重形式. 可以建立一个form表单: <form id="dropz" action=&q ...