基础

文件

后缀名
一般是 .sh ,但任何后缀名都可以,expect 的后缀一般是 exp,不影响脚本的执行。

第一行
#! 用于指定本脚本的解释器
例如
#!/bin/bash 使用 bash 执行
#!/bin/expect 使用 expect 执行

运行方式

作为可执行程序

chmod +x ./test.sh
chmod 755 ./test.sh
./test.sh

注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

作为解释器参数

/bin/sh test.sh
/bin/php test.php
/bin/expect test.exp

注释

单行

  1. # 注释

多行

  1. :<<EOF
  2. 注释
  3. 注释
  4. EOF
  5. :<<!
  6. 注释
  7. 注释
  8. !
  1. 用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
  2. {
  3. 注释
  4. name
  5. echco
  6. }

变量

定义赋值

  • 变量名与=直接不能有空格
  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线 _
  • 不能是关键字

常量赋值:
name=”abc”
ages=1
yourName=”abc”
your_name=”abc”

语句赋值
for file in ls /etc
for file in $(ls /etc)

**=** 两侧有空格是会当做命令执行

  1. name=ls
  2. echo $name
  3. # ls
  4. name= ls
  5. echo $name
  6. # a.php b.php
  7. name = ls
  8. # name:command not found

使用

$var_name
${var_name} 定义变量边界

例如:
name=111
echo $name 111
echo $name222 空
echo ${name}222 111222

只读变量

readonly name

删除变量

unset name

变量类型

运行shell时,会同时存在三种变量:

  • 1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  • 2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • 3) shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

特殊变量

变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(“ “)包含时,与 $* 稍有不同,下面将会讲到。
$? 上个命令的退出状态,或函数的返回值。
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。

|

数据类型

string

语法可以是单引号、双引号、或不带引号
name=li lei
name=’li lei’
name=”li lei”

双引号

  • 里面可以解析变量
  • 里面可以出现转义字符

单引号的限制

  • 任何字符原样输出,单引号字符串的变量将不被解析
  • 单引号字符串中不能出现单独一个单引号。

拼接

str=”hello $name”
str=”hello ${name}’s cat”
str=”hello “$name”‘s’ cat”
str=’hello ‘$name”‘s cat”

字符的长度

查看 命令替换 的文档

截取

查看 命令替换 的文档

查找

查找字符 io 的位置(哪个字母先出现就计算哪个):
string=”runoob is a great site”
echo expr index "$string" io # 4

正则提取

  1. # 过滤出11位手机号 -E 正则 -o 只输出匹配结果
  2. phone=$(echo $str | grep -Eo '/d{11}')

执行命令

  1. str='ls -al'
  2. ${str}

alias 需要使用 eval 执行

原因:查看子文章《 shell中命令的执行流程》

  1. shopt -s expand_aliases
  2. alias ll="pwd"
  3. str="ll"
  4. # ${str} ll: command not found
  5. # `$str` ll: command not found
  6. eval $str
  7. /var/wwww

数组

定义

list=(v1 v2 v3)

单行定义,逗号分隔

list2=(
v1
v2
v3
)

多行定义 一个一行

list3[0]=v1
list3[1]=v2
list3[100]=v3

单独定义数组的分量,不使用连续的下标,下标范围不限

直接在 for 语句中定义
for v in v1 v2 v3
do
done

读取

格式:${数组[下标]} 单个元素
name=${list[1]}

格式:${数组[@]} | ${数组[*]} 表示所有元素

元素个数

${#array[@]} 或 ${#name[*]}

${#array[1]} //第二个元素的长度

循环

  1. arr=(a,b,c)
  2. for s in ${arr[@]}
  3. do
  4. echo $s
  5. done
  6. for a in a b c
  7. do
  8. echo $a
  9. done

stirng to array

  1. str=a,b,c
  2. # , 替换为空格,形成 a b c 数组接头
  3. arr=(${str//,/ })
  4. for s in ${arr[@]}
  5. do
  6. echo $s
  7. done

或者

  1. #!/bin/bash
  2. string="hello,shell,split,test"
  3. #对IFS变量 进行替换处理
  4. OLD_IFS="$IFS"
  5. IFS=","
  6. array=($string)
  7. IFS="$OLD_IFS"
  8. for var in ${array[@]}
  9. do
  10. echo $var
  11. done

命令替换

命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。

diy: 定义了优先执行权

格式:$(<command>)<command>
示例:

echo today is $(date "+%Y-%m-%d")
echo today is `date "+%Y-%m-%d"`

区别:

$() ``
直观度 比较直观 容易混乱
所有系统类unix 部分支持 都支持
多层嵌套(可以混合使用) 支持 不支持

变量替换

格式: ${<变量>}

https://www.cnblogs.com/itxdm/p/something_of_shellscirpt.html

定义代码边界

firstName=li
fullName=${firstName}lei
fullName=$firstNamelei

取路径各个部分(删除部分)

可以提取出路径、文件名、后缀

# 路径
${file%/*}     #(最后一个 / 之前(左)的部分)

# 文件名
${file##*/}    #(最后一个 / 以后(右)的部分)

# 后缀名
${file##*.}    #(最后一个 . 以后(右)的部分)

file=/var/www/project/old.index.php

符号是去掉左边(在键盘上 # 在 $ 之左边)
echo ${file#/}
var/www/project/old.index.php
echo ${file##
/}
old.index.php
echo ${file#.}
index.php
echo ${file##
.}
php

% 符号是去掉右边(在键盘上 % 在 $ 之右边)
echo ${file%/}
/var/www/project
echo ${file%%/
}
(空)
echo ${file%.}
/var/www/project/old.index
echo ${file%%.
}
/var/www/project/old

单一符号是最小匹配;两个符号是最大匹配
*是用来匹配不要的字符,也就是想要去掉的那部分 还有指定字符分隔号,与*配合,决定取哪部分

变量状态赋值

变量未定义过或 unset 过 变量已赋值空
name=|name=””
:
变量已赋值非空
name=val
- 未定义过则返回 default echo ${name-default}
echo $name
default

val
val
:- 或为空 echo ${name:-default}
echo $name
default
default
val
val
+ 不为实则返回 default echo ${name+default}
echo $name

default
default
val
:+ 不为空 echo ${name:+default}
echo $name


default
val
= 为空返回 default,并将值设置为 default echo ${name=default}
echo $name
default
default

val
val
:= echo ${name:=default}
echo $name
default
default
default
default
val
val

取子串

${file:<开始点>:<长度>}
${file:<开始点>}

echo ${file:3} // 从index 为3的字符(包含)截取到默认
echo ${file:3:3} // 从index 为3的字符(包含)截取后面3个字符

替换字符串

${file/<搜索>/<替换>}
${file//<搜索>/<替换>}

${file/dir/path} / 代表单个替换
${file//dir/path} // 代表全部替换

删除字符串

${变量#关键字} 若变量内容从头开始的数据符合“关键字”,则将符合的最短数据删除
${变量##关键字} 若变量内容从头开始的数据符合“关键字”,则将符合的最长数据删除
${变量%关键字} 若变量内容从尾开始的数据符合“关键字”,则将符合的最短数据删除
${变量%%关键字} 若变量内容从尾开始的数据符合“关键字”,则将符合的最长数据删除

取长度

${#file}

$(())

整数运算

+-*/%

echo $((2+3))

a=4;b=3
echo $((a*b))
echo $(($a+$b))

进制转换

将其他进制的数转换为10进制
格式: $((<进制>#<值>))

echo $((2#110)) #6
echo $((16#2a)) #42

(())

递增递减变量

a=5;b=7
((a++))
echo a #6
((a—))
echo a #5
((aecho $? #0
((a>b))
echo $? #1

运算符

运算符 说明 举例
+ 加法 expr $a + $b 结果为 30。
- 减法 expr $a - $b 结果为 10。
* 乘法 expr $a \\* $b 结果为 200。
/ 除法 expr $b / $a 结果为 2。
% 取余 expr $b % $a 结果为 0。
= 赋值 a=$b 将把变量 b 的值赋给 a。
== 相等。用于比较两个数字,相同则返回 true。 [ $a == $b ] 返回 false。
!= 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。

|

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 true。
-ne 检测两个数是否相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。

|

运算符 说明 举例
! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
-o 或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a 与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。

|

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否为0,不为0返回 true。 [ -z $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。

|

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是具名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

|

输出

echo

下面的转义字符都可以用在 echo 中:

转义字符 含义
\\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键)
\v 垂直制表符

echo -e 可以转义上面的字符
echo -E 不转义,也是默认值
echo -n 当前命令结束后不换行

printf

命令的语法:printf format-string [arguments…]
format-string 为格式控制字符串,arguments 为参数列表。

列表

定义

格式1:空格分隔
list = a1 a2 a3

格式2:逗号分隔
list = {a1,a2,a3}

# 方式1
names = dog am

# 方式2

语句

条件语句

if [ 表达式 ]
then
#语句1

elif test 表达式
then
#语句2
else
#语句3
fi

if [ 表达式 ]; then 语句; else 语句; fi;

表达式
https://www.cnblogs.com/kaishirenshi/p/9729800.html

分支语句

case 值 in
模式1)
语句;
;;
模式2)
语句;
;;
*)
语句;
;;
esac

循环语句

for

for 值 in 列表
do
执行语句
done

列表生成方式

for i in {1 2 3 4 5 6 7 8 9 10}

for i in {1..10}

for i in $(seq 1 10)

DIR="/var"
for k in $(ls $DIR)

while

while [ 表达式 ]
do
执行语句

done

until

与while相同,只是当表达式返回false 的时候继续运行

循环控制

break n
跳出当前循环
continue
跳出本次循环

函数

https://blog.csdn.net/linyonfeng/article/details/81249762

定义函数

fuc1 () {
执行语句
}

function func2 () {
执行语句

[return 结果] //外部也可以通过$? 来获取结果

}

函数的参数
前9个通过 $n 来获取
大于9个的参数通过 ${n} 来获取

变量的生效范围

local命令是用来定义一个局部变量的,它只能定义在函数中,并且随着函数的结束而被销毁

function foo()
{
        #全局变量赋值
        a=1
    #本地变量赋值
    local b=2
}

#调用函数
foo
echo $a
#1
echo $b
#空

返回值

默认 返回值为最后一条命令的执行结果
手动指定返回码
return 0~255

其他值返回方式:

https://blog.csdn.net/weixin_33788244/article/details/92021783

函数为子程序调用+标准输出

function add()
{
        res=$1+$2
    echo $res
}

val=$(add 1000 2000)
echo $val
#3000

使用引用返回


function myfunc() 
{ 
  local __resultvar=$1 
  local myresult='some value' 
  eval $__resultvar="'$myresult'" 
}  
myfunc result 
echo $result

使用全局变量

不推荐

删除函数

当只有func_name方法时
unset func_name 可以将方法删除
当func_name方法 和fanc_name变量同时存在是
unset -f func_name 才可以将方法删除

也是就是说:usnet 语句会先删除变量,当变量不能存在时会移除同名的方法

引入其他文件

. filename

source filename

重定向

输入重定向 覆盖
>> 输出重定向 追加
< 输入重定向