Shell脚本简单入门教程

摘要: Shell脚本简单入门教程,Shell,脚本,简单,入门,教程,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 将输入流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<&-表示关闭输入文件描述符n,如0<&-或<&-表示关闭标准输出。

  |&

  |&等价于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之中信息是共享的。

  

其他相关内容

  eval

  脚本中需要使用到的命令

  用法为eval cmd args

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

  a=5

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

  eval $cmd

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

  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

本文由 帝一博客 原创发布。用户在本站发布的原创内容(包括但不仅限于回答、文章和评论),著作权均归用户本人所有。独家文章转载,请联系邮箱:17762131@qq.com。获得授权后,须注明本文地址: https://bubukou.com/mljb/1144.html

网友留言评论

0条评论