Shell script编程

[TOC]

变量

  1. 显示变量
   echo $PATH
   echo $variable
   echo ${HOME}
  1. 设置变量,注意单引双引的区别
   name=luca
   name="luca use $LANG"
   name=luca\ use\ $LANG #使用\转义空格
   version=$(uname -r)
   version=`uname -r`
   PATH=${PATH}":/home/bin"
   name=${name}ly
  1. 如果变量需要在子进程使用,需要export来使变量变成环境变量
   export PATH
  1. 查看当前shell环境中的环境变量
   env
   export
  1. 查看环境变量和自定义变量的所有变量
   set
  1. $本身是个变量,代表当前shell线程代号,echo $$

  2. $?代表上个执行命令的回传码,exit 0 #脚本返回0为成功

  3. declare来实现更改变量类型、属性等

   declare -i sum=1+2+3 #将变量定义为整数,不申明会当做字符串输出
   sum=$((1+2+3)) #这样也能计算
   sum=$[1+2+3] #这样也能计算
   
   declare -a ary #将ary定义为数组类型
   
   declare -x sum #将sum定义为环境变量
   declare +x sum #将sum从环境变量移除
   
   declare -r sum #将sum定义为只读
   delcare -p sum #列出sum的类型
  1. 变量内容的替换和删除

删除

   ${variable#a*b} variable代表变量不加$,#代表从前面开始删,且去最少匹配,*为0到多个匹配,ab代表从a字符删到b字符,包括ab在内都删  
   ${variable##a*b} ##代表按最多的删  
   ${variable%a*b} %代表从后面开始删,ab的次序和变量中的次序不变,从a删到b  
   ${variable%%a*b} %%表示按最多的删,删到最后用a*

替换

   ${variable/old/new} 在variable变量中,找到old替换成new,替换一个  
   ${variable//old/new} 替换所有

测试和替换

   ${variable-content} 如果variable被设置了,则不变,否则给variable变量设为值content  
   ${variable:-content} 同上,但是若variable已设置但是为空也会被设置为值content  
   ${variable+content} 当variable被设置了,则替换成值content,否则仍然为空  
   ${variable:+content} 同上,但是若variable已被设置但为空,仍然为空  
   var=${variable=content} 简单理解就是,当variable没被设置,var=variable,且都等于content;当variable已被设置,var=variable,且他们都等于variable原来的值  
   var=${variable:=content} 简单理解就是和上面一样,但是当variable虽然被设置了但是为空时,variable和var相等,且都被赋值为content  
   var=${str?expr} 当str没被设置时,expr输出到stderr标准错误输出,否则var=str  
   var=${str:?expr} 和上面一样,但是当str为空时也会输出到stderr
  1. 变量长度

    len=${#variable}
    
  2. 变量作用范围

    全局环境变量:对所有shell可见,使用env查看。系统环境变量一律使用大写来区别用户创建的环境变量。
    局部变量:只对创建他的shell可见

    在某个shell进程中创建的局部变量,进程内可见。

    脚本中定义的变量后面的函数可见

    函数中定义的变量后面可见

    函数中local var=1函数内可见

    函数内外local且同名,互不影响
    变量需要export才能被子进程看到,export PATH后,PATH则相当于$_GET,任何脚本都能直接得到。

    unset一个全局环境变量的时候,只会在当前shell进程中有效。

数组

  1. 设置数组
   var[1]=one
   var[2]=two
   echo ${var[1]} #one
   echo $var
  1. 同时设置
   var=(one two three four six)
   echo $var #one
   echo $var[2] #three
   echo ${var[*]} #one two three four six
   unset var[2]
   echo $var[2] #
   echo ${var[*]} #one two four six
   unset var
   echo ${var[*]} #

MISC

  1. #! /usr/bin/bash

指明解释器的名称,这儿是bash,同理还能是#! /usr/bin/python,#! /bin/awk等

#!用来指明脚本交给哪个解释器执行

  1. exit 0用来将程序中断,并回传一个数值给系统

  2. bash a.sh在子进程中进行,等效于sh a.sh,或者直接调用脚本./script.sh
    source a.sh在父进程中进行,等效于. a.sh

  3. bash启动的时候会默认处理如下文件

/etc/profile

$HOME/.bash_profile

$HOME/.bash_login

$HOME/.profile

第一个是bash一般都会执行的,后面三个是用户专有,可以定制。

.bash_profile会去执行.bashrc的内容,当是交互式shell的时候不会去访问/etc/profile,而是去访问这个文件

  1. ps命令 ps命令有三种风格,第一种Unix风格带一个-,BSD风格不带-,GUN风格带全参数,比如–deselect

Unix风格主要记住几个参数

-e显示所有进程

-f显示完整格式

-H显示层级格式,能显示父进程

ps -efH

BSD风格主要记住

a和任意终端相关的所有进程

x显示所有进程,包括未分配终端的进程

u基于用户的格式显示

f按照分层格式显示进程

ps auxf

  1. echo

echo -e “asas” #-e是为了转义,当其中出现的时候会使用转义来实现文字效果等

echo -n “test” #-n是清除结尾换行

  1. find

find . -mtime -1 #查找当前目录下最后修改日期在一天内的文件或目录,-n是n天内,+n是n天以前

  1. >/dev/null 2>&1

1是默认标准输出,所以>/dev/null等同于1>/dev/null,&相当于等同于的意思,2>&1就是错误输出等同于1的处理的意思

判断符号和判断式

判断句子返回true或者false,用在任何需要判断是否的地方

  1. test命令

test -e /file && echo "exist" || echo "Not exist"

判断文件

-e exist,文件是否存在 -f file,是否为文件 -d dir,是否为目录 -b block device,是否为一个block device设备 -c character device -S Socket文件 -p pipe,是否为一个FIFO(pipe)文件 -L link,是否为一个连接文件

判断文件权限

-r read,是否为可读 -w write,是否为可写 -x 是否可执行 -u SUID属性 -g SGID属性 -k 是否具有Sticky bit属性 -s 检测该文件是否存在且为非空白文件 -O ownership,检查运行脚本的是否为属主

判断两个文件 test file -nt file1

-nt newer than -ot older than -ef 是否为同一文件,hard link的判定上

两个整数间的比较 test n1 -eq n2

-eq equal,== -ne not equal,!= -gt greater than,> -lt less than,< -ge greater than or equal,>= -le less than or equal,<=

判断字符串

test -z string 判定字符串是否为0,若为空返回true,只要不是空都返回false test -n string 和上面相反,为空返回false,默认省略-n test str1=str2 判定两字符串是否相等,判断式中=和==等效。两个字符串都要用双引号括起来,免得变量中间有空格的情况出现出现错误 test str1!=str2 判定两字符串是否不等于

多重条件判定 test -r file -a -x file

-a 等效&& and -o 等效|| or ! 反向,test ! -x file

  1. []判断符号

    格式:[ -z “$HOME” ],必须注意每个关键字左右都得有空格

    [ -e ./file ] && echo "exist" || echo "Not exist"

    其余语法和上面一致

结构化命令

  1. if语法
   if command
   then
       commands
   fi
   
   
   if command
   then
       commands
   else
       commands
   fi
   
   
   if command
   then
       commands
   elif command
   then 
       commands
   fi
  1. if-then高级性质

(( expression ))可用于判断计算数值计算后的true、false以及数值计算的赋值

   if (( $val  ** 2 > 90 ))
   then
       (( val2 = $val ** 2 ))
   fi

[[ expression ]]可用于字符串比较,除了标准的字符串比较嗨提供了模式匹配

   if [[ $USER == r* ]]
   then
       echo "yes"
   else
       echo "no"
   fi
  1. case语法
   case variable in
   pattern1 | pattern2)
       commands1;;
   pattern3)
       commands2;;
   *)
       default commands;;
   esac
  1. for命令,这儿的list可以是字符串(用空格分开或自定义分隔符),cat file,/home/*等
   for var in list
   do
       commands
   done
  1. C风格for命令
   for (( variable assignment; condition; iteration process ))
   do
       commands
   done
  1. while命令
   while test command
   do
       other commands
   done
  1. until命令

  2. break跳出循环,continue跳出本次循环

  3. done后可以处理重定向,done>a.text

函数

  1. 定义,同名函数会覆盖上面的
   function name {
       commands
   }
  1. 使用
   name arg1 arg2
  1. 返回值

首先,默认情况下是由函数内最后一条命令返回作为回传码。

其次可以使用return返回一个整数值来定义退出状态码。退出码在0-255之间

还有一种方法能把字符串或者整数等输出给别的变量。这样会将值传给return,函数中所有echo都会传给return

   function db1{
       echo $[$1*2]
   }
   
   return=`db1`
  1. 参数

$0 函数名

$n 第n个参数

$# 参数个数

$@全部参数

这些定义和脚本运行的传参不同,虽然代表的意义一样

  1. 定义域

函数内外的变量都是全局的,任意修改影响全局。是很危险的。

所以一般建议函数内部的变量设置为局部变量,添加关键词

   local temp
  1. 数组当做函数的参数
   db1 ${var[*]}
  1. 函数返回数组
   function db1{
       var=(`echo $@`)
       echo ${var[*]}
   }
   ary=(a b c d e)
   arg=`echo ${ary[*]}`
   return=(`db1 $arg`)
  1. 递归

  2. 库函数使用source来被加载到新脚本中

   ../funcs

← 习惯Mac  安装软件程序 →