@yangfch3
2017-01-14T19:01:31.000000Z
字数 5501
阅读 5232
shell
学习任何一门语言的基础都是:
所以,当新接触 Shell 编程,无非就是把这些在其他语言里学到的东西迁移与本土化。
sh/bash/zsh Shell 编程的局限
所以我们平时基本只使用 sh/bash 这些 Shell 语言 脚本来做一些轻量、自动化、琐碎的工作。
=
前后不能空格Shell 负责与接收我们输入的命令,翻译成内核能接受的形式,帮助我们与内核(通过)Shell 命令/工具交流。
Shell 的语句以 ;
分隔或者换行以区分!
引号
注释以 #
为特征字符,但注释有两种用途:
放在 shell 文件头部指引解释器优先级
#!/bin/bash
#!/bin/sh
普通注释
# Author: yangfch3
# Copyright (c) http://yangfch3.com/
定义变量和使用变量存在着一定的规则
注意:变量名和等号之间不能有空格
变量命名规则:
$
后接变量名${}
包住变量名推荐采用第二种写法,确保解析正确(帮助解释器识别变量的边界)。
name="yangfch3"
echo "${name}"
使用未定义的变量,则变量值为空
echo "${name}"
与定义变量的方法一致,支持变量的复写
name="yangfch3"
name="${name}@github"
echo "${name}"
复写的变量的值就进行了更新
使用 readonly
关键字可以将一个变量设为只读
name="yangfch3"
readonly name
或者直接放到变量前
readonly name="yangfch3"
如果你对只读的变量进行了复写,脚本会运行出错:
./main.sh: line 8: var1: readonly variable
使用 unset
可以删除变量
unset variable_name
1. 局部变量
在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2. 环境变量
所有的程序,包括 shell 启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候 shell 脚本也可以定义环境变量。
3. shell 变量
shell 变量是由 shell 程序设置的特殊变量(见特殊变量一节)。shell 变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了 shell 的正常运行
特殊变量列表
命令行参数用 $n
表示,例如,$1
表示第一个参数,$2
表示第二个参数,依次类推。
echo "$1$2"
$ ./main.sh var1
var1
当 $n
中 n 的值小于参数个数时,$n
为空 ""
1. 不被双引号包含时
$*
和 $@
都表示 传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1
" "$2
" … "$n
" 的形式输出所有参数。
2. 被双引号包含时
当它们被双引号(" ")包含时,"$*
" 会将所有的参数作为一个整体,以"$1
$2
… $n
"的形式输出所有参数;"$@
" 会将各个参数分开,以"$1
" "$2
" … "$n
" 的形式输出所有参数。
echo "print each param from \$*"
for var in $*
do
echo "$var"
done
echo "print each param from \$@"
for var in $@
do
echo "$var"
done
echo "print each param from \"\$*\""
for var in "$*"
do
echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
echo "$var"
done
输出:
print each param from $*
a
b
c
print each param from $@
a
b
c
print each param from "$*"
a b c
print each param from "$@"
a
b
c
$?
可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。
退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0
,失败返回 1
。
不过,也有一些命令返回其他值,表示不同类型的错误。
$ echo $?
0
$?
也可以表示函数的返回值(同脚本执行完毕相似)。
$0
:当前脚本的文件名
$$
:当前 shell 进程 ID
$#
:传入的参数的个数
$ ./main.sh a b c
$0= ./main.sh
$#= 3
$$= 3333
类似于 ES6 里的模板字符串,shell 里的字符串内可以包含变量、转义字符……
echo -e "a\nb\nc"
注意:转义字符要想转换成功,需要为 echo 添加 -e 参数
命令替换是指 Shell 可以先执行命令,将输出结果暂时保存在变量中,在适当的地方输出或使用。
作用类似 ES6 里的模板字符串。需要将命令执行标准输出作为变量值得就是用 ``。
命令替换有两种模式:
$(put your command)
(推荐)
echo "There are $(ls | wc -l) items here."
UP=`date ; uptime`
echo "Uptime is $UP"
变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值
echo ${var:-"Variable is not set"}
echo "1 - Value of var is ${var}"
echo ${var:="Variable is not set"}
echo "2 - Value of var is ${var}"
unset var # 删除变量 var
echo ${var:+"This is default value"}
echo "3 - Value of var is $var"
var="Prefix"
echo ${var:+"This is default value"}
echo "4 - Value of var is $var"
echo ${var:?"Print this message"}
echo "5 - Value of var is ${var}"
输出:
Variable is not set
1 - Value of var is
Variable is not set
2 - Value of var is Variable is not set
3 - Value of var is
This is default value
4 - Value of var is Prefix
Prefix
5 - Value of var is Prefix
我们可以在读取变量时对变量内部进行字符串代换:
echo ${Variable/Some/A}
# 会把 Variable 中首次出现的 "some" 替换成 “A”
我们也可以在读取变量时对变量字符串进行截取
# 变量的截取
Length=7
echo ${Variable:0:Length}
# 这样会仅返回变量值的前7个字符
字符串的形式有如下几种:
区别其实比较容易区分,根据形式的特点决定使用何种方式。
无引号
单引号字符串的特点:
name='yangfch3'
echo '\n${name}';
输出
\n${name}
双引号的特点:
双引号里内可以有 变量
双引号内变量可以再用双引号包住,也可以不包。
双引号里可以出现 转义字符
注意:shell 编程里没有所谓的字符串 +
的概念,直接在双引号内进行字符串拼接。
name="yangfch3"
# 双引号递归匹配,内部双引号不会输出
greeting="hello, "${name}" !"
greeting_1="hello, ${name} !"
echo $greeting $greeting_1
输出
hello, yangfch3 ! hello, yangfch3 !
string="abcd"
echo ${#string} # 输出 4
string="xxx is a yyy"
echo ${string:1:4} # 输出 xx i
string="xxx is a yyy"
echo `expr index "$string" is` # 输出 4
bash 支持一维数组(不支持多维数组),并且没有限定数组的大小。
# 形式1
arr1=("0" "1" "``expr 2 + 2")
# 形式2
array_name=(
0
1
`expr 2 + 2`
)
# 形式3:单独定义数组分量
array_name[0]=0
array_name[1]=1
array_name[2]=`expr 2 + 2`
读取数组单项:${array_name[index]}
读取数组所有项:${array_name[*]}
${array_name[@]}
读取数组的长度:${#array_name[@]}
length=${#array_name[*]}
读取数组单个元素的长度:lengthn=${#array_name[n]}
原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk
和 expr
,expr
最常用。
使用 expr
进行运算时需要使用上面提到的命令替换
`expr 2 + 2`
[]
在变量声明与分支判断时,内部也可以使用运算符:
num1=$[2*3] # 变量声明 [] 内部使用算术运算符
if [num1 -eq 6] # 分支判断 [] 内使用运算符
then
echo num1
fi
()
内部也可以包裹运算 两点注意:
2+2
是不对的,必须写成 2 + 2
,这与我们熟悉的大多数编程语言不一样。`,我们还可以使用
()来包裹运算,如:
(2 + 2)`
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
if [ $a == $b ]
then
echo "a is equal to b"
fi
*
前边必须加反斜杠 \
才能实现乘法运算;关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
Shell 里对数值和字符串不做区分,或者说数值一般情况下视为字符串,再运算时才被当做数值。
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a is equal to b"
else
echo "$a -eq $b: a is not equal to b"
fi
a=10
b=20
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a -lt 100 -a $b -gt 15 : returns true"
else
echo "$a -lt 100 -a $b -gt 15 : returns false"
fi
在分支条件那里,我们可以使用 &&
和 ||
来进行 短路的逻辑运算。
# 在 if 语句中使用 && 和 || 需要多对方括号
if [ $Name == "Steve" ] && [ $Age -eq 15 ]
then
echo "This will run if $Name is Steve AND $Age is 15."
fi
if [ $Name == "Daniya" ] || [ $Name == "Zach" ]
then
echo "This will run if $Name is Daniya OR Zach."
fi
a="abc"
b="efg"
if [ -z $a ]
then
...
fi
文件测试运算符用于检测 Unix 文件的各种属性。依赖文件 path 字符串。
file="./test.sh"
if [ -r $file ]
then
echo "File has read access"
else
echo "File does not have read access"
fi
xx 分钟系列:
手册系列: