linux 制作shell脚本教程,Shell脚本简单入门教程

Shell脚本简单入门教程,如果你分不清shell是什么,此文一定不适合你。毕竟只花了十多分钟看的教程,不会涉及细节,细节将在以后的使用中逐渐以示例形式给出。

PS:借来的东西,果然迟早是要还的。刚在linux下学习时,为了批量处理,当时会C语言,就用C语言编个程序实现,心想虽然不会shell,不是也很方便嘛。然后会了C++,发现比C用起来方便多了。再然后越来越的批处理工作需要程序,C++有点太大杀气了,Python这么火,而且也很强大,学了肯定不白学,遂各种自动化的工作就交给了Python。然后最近发现Python这货也有点太大杀所了,我只是想写个简单的自动化指令而已。所以现在来还当年欠下的shell。假如你也如此,还是花上几十分钟,掌握一把小刀,何乐而不为呢。

关于

记得脚本最前面添加shell解释器,通常为sh、bash,其他的不常见,依然先给个HelloWorld

#!/bin/sh

echo "HelloWorld" #我是注释

然后给了执行权限即可直接执行,或者手动通过sh script.sh来执行,shell脚本后缀通常为.sh。当然Linux下面文件只要有了可执行权限(chmod +x file),什么后缀都没有影响。

我们平时使用的terminal其实就是个shell解释器的交互窗口,所以学习shell编程直接开个terminal就可以开编了。shell中可以直接执行任何linux/unix命令(其实这些命令就是shell内部的)正是它方便之处

变量

shell变量不分类型,默认都是字符串。单引号的字符串类似raw字符串,不能解析转义字符及变量。不被引号引住的字符串中不能用空格。

变量定义形如:变量名=值,等号中间不能有空格。变量名要求即编程语言的常规要求

变量引用则直接在变量名前加$符号,为了限定shell解释器解释变量名的边界可以用大括号包围变量名:${变量名}

ex:

var="maxwi"e

cho "Hello ${var}.com"

字符串

在shell的语句中间执行命令只需要将命令放在”`”(ESC下面那个键)之间即可,当然任何命令都可以在命令前面没有内容时直接执行:

cd $HOME;ls #进入个人目录并执行ls

var=`ls` #ls结果以空格分隔的字符串返回给var

for file in $var # for...in循环输出以空格分隔的字符串内容

do

echo $filed

one

多个命令通过分号(;)并入一行执行

只读变量

var=8

readonly var

var=9 #出错

删除变量

unset var

拼接字符直接将其放在一起即可

a=I

b='love'

c="China"

d="$a $b $c"

echo $d

输出:I love China

获取字符串长

echo ${#var}

字符串切片

echo ${var:2:5}

注意字符串中字符是从0计数,上述切片内容是从第3个字符到第6个字符,包含位置2和5位置上的字符

数组

数组下标从0开始,使用小括号(())定义数组,元素以空格或回车分隔:arr=(val1, val2, val3)

使用下标获取相应元素:${arr[index]}

获取数组中的所有元素echo ${arr[@]}或echo ${arr[*]}

获取数组长度:

echo ${#arr[@]}

当然里面可以是*

for...in循环可以用于遍历数组中的元素

var=(1 2 3 I 'love' "China")

for v in ${var[@]}

do

str="$str $v"

done

echo $str

输出:

1 2 3 I love China

命令行参数

通过$n来访问传递给shell脚本的命令行参数,$0为脚本本身,下面为几个特殊的参数:

参数

功能

$#

传递到脚本的参数个数

$*

以一个单字符串显示所有向脚本传递的参数。如”$*”用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。即无法用for…in遍历每一个元素

$$

脚本运行的当前进程ID号

$!

后台运行的最后一个进程的ID号

$@

与$*相同,但是使用时加引号,并在引号中返回每个参数。 如”$@”用「”」括起来的情况、以”$1” “$2” … “$n” 的形式输出所有参数。

$-

显示Shell使用的当前选项,与set命令功能相同。

$?

显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。”

运算符

数字关系运算符

该运算符只支持数字:

运算符

说明

举例

-eq

检测两个数是否相等,相等返回 true。

[ $a -eq $b ] 返回 false。

-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。

也可以使用==和!=

注意使用时必须使用方括号括住

eg:

a=1

b=2

if [ $a -eq $b ]

then

echo "$a -eq $b : a 等于 b"

else

echo "$a -eq $b: a 不等于 b"

fi

布尔运算符

! 取非,如[!false]返回true

-o 或运算

-a 与运算

逻辑运行符

&& 逻辑与

|| 逻辑或

字符串比较运算符

运算符

说明

举例

=

检测两个字符串是否相等,相等返回 true。

[ $a = $b ] 返回 false。

!=

检测两个字符串是否相等,不相等返回 true。

[ $a != $b ] 返回 true。

-z

检测字符串长度是否为0,为0返回 true。

[ -z $a ] 返回 false。

-n

检测字符串长度是否为0,不为0返回 true。

[ -n $a ] 返回 true。

str

检测字符串是否为空,不为空返回 true。

[ $a ] 返回 true。

文件测试运算符

常用的几个

[-f file] 检测文件是否为普通文件,既不能是目录也不能是设备

[-d file] 检测是否为目录

[-s file] 检测文件是否为空

[-e file] 检测文件是否存在

[-r file] 检测文件是否可读

[-w file] 检测文件是否可写

[-x file] 检测文件是否可执行

通过expr实现的算术运行符

expr命令可以执行算术表达式并返回结果

如:

a=1

b=2

val=`expr $a + $b`

val=`expr 9 * $b`

注意乘运算需要有转义符,表达示之间必须用空格隔开

输入、输出控制

输出

echo默认输出会换行,可以使用c转义实现不换行

可以通过echo直接回显命令执行结果:

echo `date`

可以使用linux下类型C语言中printf的格式控制输出命令,详见man printf

输入

通过read读取输入:

echo 'Input number'

read a b c d

如果输入为1 2 3 4 5 6,则a,b,c分别为1,2,3,但d是4 5 6

文件重定向

shell的重定向功能非常强大,重定向命令列表如下:

命令

说明

command > file

将标准输出重定向到file。

command < file

将标准输入重定向到file。

command >> file

将输出以追加的方式重定向到 file。

n>file

将文件描述符为n的文件重定向到 file。注意不能有空格,下同

n>>file

将文件描述符为 n 的文件以追加的方式重定向到 file。

n>&m

将输出流n合并到m。可以理解为使用&n来引用名为n的文件描述符,即将文件描述符n重定向到文件描述符m

n

将输入流m合并到n。

<< tag

将开始标记 tag 和结束标记 tag 之间的内容作为输入。

文件描述符0通常是标准输入(stdin),1是标准输出(stdout),2是标准错误输出(stderr),/dev/null为黑洞文件,所有写入到它的内容都会被丢弃,如果不指定数字,则默认为输出为1,输入为0

查看系统文件描述符路径:ls /proc/self/fd/ -l

几个特殊的用法:

n>&-

n>&-表示关闭输出文件描述符n,如1>&-或>&-表示关闭标准输出;类似的n

|&

|&等价于2>&1,即将标准错误合并到标准输出并作为管道的标准输入,输出结果中标准错误将在标准输出的前面,用法为cmd1 |& cmd2,cmd2将以cmd1的输出和错误输出作为输入。

&>/dev/null

&>/dev/null等价于>/dev/null 2>&1,即将标准输出和错误输出重定向到null,什么也不会输出

>/dev/null

等价于1>/dev/null,即将标准输出重定向到null,只会输出标准错误

举例:

1.cat ss.py > cat_test.txt,获取文件ss.py中的内容,并将其重定向到文件cat_test.txt,由于没有指定文件描述符,所以默认为将cat输出到标准输出中的内容重定向到文件。其等价于cat ss.py 1>cat_test.txt。

2.ls tes ss.py 1>out.txt 2>err.txt 表示将标准输出输出到文件out.txt,标准错误输出到文件err.txt

3.ls tes ss.py > oe.txt 2>&1 表示将标准错误输出重定向到标准输出,并将标准输出重定向到文件oe.txt。

4.ls tes ss.py 1>&- 2>&- 关闭标准输出和错误输出,效果等价于以下几个命令ls tes ss.py 1>/dev/null 2>/dev/null,ls tes ss.py 1>/dev/null 2>&1,ls tes ss.py >/dev/null 2>&1, ls tes ss.py &>/dev/null

5.cat > t.txt 将标准输入重定向到t.txt,输入内容之后,通过ctrl+d发送文件结束符停止输入。

6.cat > t.txt < ss.py 从ss.py读取数据,并重定向到t.txt

Here Document是shell用于将delimiter之间的内容重定向到命令的特殊重定向:

command << delimiter

document

delimiter

注意,第二个delimiter必须顶格写,这样其之间的document内容将都会传递给command

修改当前shell session下的所有命令重定向

exec 1>out.txt,执行之后会将当前shell窗口下执行的所有命令的标准输出内容重定向到文件out.txt,而在命令行窗口中不会输出任何内容。可以通过关闭当前shell终端并重新开一个来解决。也可以通过提前将标准输出绑定到一个新的文件描述符,重定向到文件之后,再将其绑回来的方式解决。

如:

exec 6>&1,将6绑定到标准输出1,可以通过ls /proc/self/fd/ -l查看。

exec 1>out.txt,进行一些操作,发现没有输出,实际上结果都在out.txt中

exec 1>&6,将1绑定到文件描述符6,其实就是最初是标准输出

exec 6>&- 现关闭文件描述符6即可

控制流

if

一个完整的if控制流程:

if condition1

then

command1

elif condition2

then

command2

else

commandN

fi

for..in

for var in item1 item2 ... itemN

do

command1

command2 ... commandN

done

列表也可以是文件名

for()

for((i=1;i<=10;i++));do echo $(expr $i * 4);done

while

while condition

do

command

done

三种死循环:

while :

do

command

done

while true

do

command

done

for (( ; ; ))

until

until condition

do

command

done

条件为真是停止,类似do..while,循环体至少执行一次

case

case 值 in

模式1)

command1

command2

...

commandN ;;

模式2)

command1

command2

...

commandN ;;

esac

每一个格式后面为右括号结束,模式匹配后一直执行,直到;;(与break功能一样)然后执行*)后面的命令,不再匹配 其他选项。

支持break、continue

函数

函数的定义方式为:

func() {

command return val

}

调用直接函数名后跟参数列表即可:

func arg1 arg2

参数性质与上面说的命令行参数一样,也有那几个特殊参数

注意参数超过10个时必须使用{}引用,如${10}

函数返回值通过$?

add() {

return $(($1+$2))

}

调用:

add 3 5

echo $?

Shell多脚本内容共享

当有两个shell脚本文件时,可以通过. filename或source filename来引用另一个文件中的代码,其实就是同一个shell session之中信息是共享的。

其他相关内容

脚本中需要使用到的命令

用法为 cmd args

该命令后面跟的所有内容都做为其参数,它会对后面的内容(即cmd args)进行两次扫描,第一次扫描将其中的变量替换为实际值,所以如果args中含有需要在bash中执行的以$开头的内容,应该加上转换符(),以避免被替换,例如如果cmd为awk,而awk是通过$来进行参数过滤的。第二次扫描时将后面的所有内容当作同一个命令组合来执行,相当于你直接在命令行中执行该命令。例如脚本如下:

a=5

cmd="echo $a | cat > tcat.txt"

$cmd

如果对cmd的执行不通过调用,而是直接$cmd,输出结果为5 | cat > tcat.txt。这显然不是我们想要的,shell将echo后面的所有内容当成了echo参数来执行。这种情况就需要使用。

exec

与source功能有点相反,source命令会在当前shell进程的上下文件环境中执行各命令。而exec虽然也不会创建新的进程,但会清除当前shell进程的上下文件内容,并执行相应命令。当然它也可以用来对文件描述符进行操作,上文已经提及。

declare(typeset)

内建命令declare与typeset功能类似,用于为变量指定类型,因为默认所有变量都会被当成字符串,当然数组除外。

用法:

declare [-aAfFgilnrtux] [-p] [name[=value] ...]

typeset [-aAfFgilnrtux] [-p] [name[=value] ...]

例如:

$ a=1

$ b=2

$ echo $a+$b

1+2

$ declare -i a=1

$ declare -i b=2

$ declare -i c

$ c=$a+$b

$ echo $c

3

local

用于在shell函数内部声明该变量为局部变量,只对当前函数或其子进程有效。用法:

local [option] [name[=value] ...]

option为declare可以接受的选项。

一不小心这里就会有一个很大的坑,因为默认情况下shell中的变量作用域是全局的,所以你一个for用了i,然后又在另一个函数调用中用了i,那这个i就会被前面的i覆盖,所以尽量在函数中有类似情况的地方用local

用例

输出系统中的所有磁盘

disks=`fdisk -l | grep 'Disk /dev/' | grep -oP '/dev/.{3}'`

for disk in $disks

do

echo '**'

echo $disk

echo '**'

done

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值