Shell 语法

  Shell程序设计作为一种脚本语言,在Linux系统中有广泛的应用,本文记录了关于Shell程序设计的基础语法知识和常用命令,方便查询,熟练使用shell也需要经常实践,这对于完成一些较简单的编程任务很有帮助。


(1)变量

  在shell里,使用变量之前并不需要事先做出声明,可以通过使用直接创建。默认情况下,所有的变量都被当做字符串进行存储,变量名区分大小写。变量名之前加一个$符号可以访问它的内容。

  输入和输出:可以使用echo命令将一个变量的内容输出到终端,使用read命令(停下来等待用户输入)可以将用户的输入赋值给一个变量。

  单引号和双引号:shell脚本的文件参数以空白符进行分割,如果一个参数包含空白符,就需要放到引号中(防止被解读为不同的参数)。双引号通常可以用来做字符串定界符。而像$salutation这样的变量放到引号中,有这几种情况:不加引号引用变量的值,放到双引号中也引用变量的值,放到单引号中就不引用,而是看作一个字符串。

$ salutation=Hello
$ echo $salutation # 输出 Hello
$ salutation="Yes Sir"
$ echo $salutation # 输出 Yes Sir
$ salutation=7+2
$ echo $salutation # 输出 7+2 (作为字符串看待)
# 使用引号:
$ myvar="Hello World"
$ echo $myvar # 输出 Hello World
$ echo "$myvar" # 输出 Hello World
$ echo '$myvar' # 输出 $myvar
$ echo \$myvar # 转义字符,输出 $myvar

  除了自定义变量外,shell还有一些环境变量和参数变量。

  所谓环境变量,就是指脚本开始执行时,一些变量会根据当前环境设置中的值进行初始化。使用export命令可以设置环境变量。下面的示例展示了常用的环境变量:

$ echo $HOME # 当前用户的home目录,在我的机器上输出 /home/gzshan
$ echo $PATH # 以冒号分割的用来搜索命令的目录列表
$ echo $0 # shell脚本的名字
$ echo $# # 传递给脚本的参数数量,默认是0
$ echo $$ # shell脚本的进程号

  所谓参数变量,就是指执行脚本程序如果带有参数,一些额外的变量会被创建,如下所示:

如:运行一个脚本的命令:./first.sh foo bar baz
$1 $2 $3 #分别指的就是参数foo,bar和baz
$# # 此时为3
$@ # 用于列出所有的参数变量,($* 也有相同功能,但受空白符影响,一般用$@)

(2)条件

  条件判断是程序设计语言控制结构的基础,程序需要对条件进行测试和判断,从而执行不同的命令,完成不同的功能和任务。在shell脚本中,完成条件测试有两个命令:test 和 布尔判断命令 [ ]

  • test 命令

      以下的例子展示了test命令的用法,注意如果then和if放在同一行则需要一个分号。

    if test -f fred.c # 如果then写在这一行需要一个分号,这条语句检查一个文件是否存在
    then
    echo "Hello"
    fi
  • 布尔判断命令[ ]

      把 [ 当作一条命令看起来有些奇怪,但是会使得程序变得简单。注意:使用 [ 时,后面必须有空格,还应该使用 ] 来结尾。

    if [ -f fred.c ] ; then # 同样必须有分号,必须有空格
    echo "test"
    fi

      当使用以上两个命令时,可以使用的条件类型归结为三类,用下表归纳。

第一类:字符串的比较 比较结果
string1 = string2 两个字符串相同结果为真
string1 != string2 两个字符串不相同结果为真
-n string 字符串不为空则结果为真
-z string 字符串为null则结果为真
第二类:算术比较 比较结果
expression1 -eq expression2 两个表达式结果相等为真
expression1 -nq expression2 两个表达式结果不相等为真
expression1 -gt expression2 expression1 大于 expression2 为真
expression1 -ge expression2 expression1 大于等于 expression2 为真
expression1 -lt expression2 expression1 小于 expression2 为真
expression1 -le expression2 expression1 小于等于 expression2 为真
!expression expression为假则结果为真
第三类:与文件有关的条件测试 比较结果
-d file 文件是一个目录,则结果为真
-f file 文件是一个普通文件,则结果为真
-g file 文件set-group-id 被设置,则结果为真
-u file 文件set-user-id 被设置,则结果为真
-s file 文件大小不为0,则结果为真
-r / -w / -x file 文件可读 / 可写 / 可执行,则结果为真
-a file 文件存在,则结果为为真
-c file 文件存在并且为字符特殊文件,则结果为真

(3)控制结构

  • if 语句和elif 语句

      if 语句比较简单,下面的例子展示了if 语句和elif语句的用法。

    #!/bin/sh
    echo "Is it morning? Please answer yes or no"
    read timeofday
    if [ $timeofday = "yes" ] # if语句,后面跟条件测试
    then
    echo "Good morning"
    elif [ $timeofday = "no" ]; then # then放同一行,加分号
    echo "Good afternoon"
    else
    echo "Sorry,$timeofday not recognized. Enter yes or no"
    exit 1
    fi
    exit 0
  • for 语句

      for语句用以循环处理一组值,这组值可以是任意字符串的集合,也可以是其他命令的输出结果,下面用两个例子展示其用法。

    #!/bin/sh
    for foo in bar fud 43 # 循环处理一组字符串
    do
    echo $foo
    done
    exit 0
    #!/bin/sh
    for file in $(ls f*.sh); do # 使用通配符扩展for循环,列出所有以f开头,扩展名为.sh的脚本文件
    # 说明:$()是执行该命令得到的输出结果
    lpr $file # lpr是打印命令
    done
    exit 0
  • while 语句

      如果事先不知道循环次数,for循环不太好使用的情况下,可以使用while循环。whie语句的do和done之间的语句反复执行,直到条件不再真为止。

    #!/bin/sh
    echo "Enter password"
    read trythis
    while [ $trythis != "secret" ]; do # 反复执行,直到条件不再真为止
    echo "sorry,try again"
    read trythis
    done
    exit 0
  • until 语句

      until语句与while循环类似,所不同的是,until反复执行循环直到条件为真。

    #!/bin/sh
    until who | grep "$1" > /dev/null
    do
    sleep 60
    done
    echo -e '\a'
    echo "$1 has just logged in"
    exit 0
  • case 语句

      case语句相比其他结构较为复杂,用下面的例子来介绍他的用法,需要特别注意的是:case按顺序查找第一个匹配的模式,而不是最佳匹配。

    #!/bin/sh
    echo "Is it morning? Please answer yes or no"
    read timeofday
    case "$timeofday" in
    yes | y | Yes | YES ) echo "good morning";; # 注意每个模式末尾是两个分号
    n* | N* ) echo "good afternoon";;
    * ) echo "sorry,answer not recognized";;
    esac
    exit 0
  • 命令列表

      有时需要将多个命令连接成一个序列,shell提供了命令列表,也就是and列表和or列表,类似于其他程序设计语言,它们也采用的是短路求值。

    if [ -f file1 ] && echo "hello" && [ -f file2 ] && echo "here";then
    echo "in if"
    fi if [ -f file ] || echo "hello" || echo "here" ; then
    echo "in if"
    fi
  • 语句块

      在某些只允许使用单个语句的地方,要想使用多条语句,可以放到花括号中构建一个语句块。

    get_confirm && { # and列表中使用语句块
    echo "hello"
    cat test.txt
    }

(4)函数

  要在shell脚本中使用函数,只需要写出函数名,然后跟一对括号,再把函数中的语句放在一对花括号中,并且把函数定义放到函数调用之前。函数体内可以用local关键字声明局部变量。

  函数参数:当一个函数被调用时,脚本程序的位置参数($*,$@,$#,$1,$2等等)会被替换为函数的参数,当函数执行完毕后,这些参数会恢复为先前的值。下面的例子展示了函数的用法。

#!/bin/sh
yes_or_no(){ # 函数定义
echo "Is your name $* ?"
while true
do
echo -n "Enter yes or no: "
read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "Answer yes or no"
esac
done
}
# 以下是主程序部分:
echo "Original parameters are $*"
if yes_or_no "$1"
then
echo "Hi $1,nice name"
else
echo "Never mind"
fi
exit 0

(5)命令

  • break命令和continue命令

      这两条命令比较简单,break应用于跳出for、while、until循环,continue命令用于跳过当前这一次循环。

  • : 命令

      :相当于一个空命令,或者相当于true的别名,例如 while : 就代表一个死循环

  • . 命令

      . 命令用于在当前shell中执行命令,如前面用到的./first.sh

  • echo 命令和read命令

      echo命令用于输出结尾带有换行符的字符串,前面已多次用到,它还有两个常用的参数,如下所示。现在最新版本的shell常常用printf来代替echo。read命令用于将用户的输入赋给一个变量。

    $ echo -n "string to output" # 去掉换行符
    $ echo -e "string to output\c" # -e确保启用了反斜杠转移字符
  • eval 命令

      eval命令用于对参数进行求值,它是shell的内置命令,通常不会以单独命令的形式存在,以下的例子展示eval的用法。eval命令就像一个额外的$,它给出一个变量的值的值。

    foo=10
    x=foo
    y='$'$x # $x就是foo
    echo $y # 输出的是$foo
    eval z='$'$x
    echo $z # 输出的是10
  • exec 命令

      exec命令时执行一个shell程序,也就是将当前shell替换为一个不同的程序,当前脚本程序exec命令之后的代码都不会执行。还有一种用法是,它可以用于修改文件描述符,比较少见。

  • exit n 命令

      exit命令使脚本程序以退出码n结束运行。退出码0表示成功,1~125是错误代码,126代表文件不可执行,127代表命令未找到。

  • export 命令

      export命令将自己的参数建为一个环境变量,而这个环境变量可以被当前程序调用的其他脚本或者程序看到。

    # 以下是export2.sh
    #!/bin/sh
    echo $foo
    echo $bar # 以下是export1.sh
    #!/bin/sh
    foo = "foo foo foo"
    export bar = "bar bar bar"
    export2 # 调用脚本2
    # 此时如果执行脚本1,我们会看到输出bar的值,因为被声明为环境变量,在脚本2中可见,而foo不会被输出
  • expr 命令和$( )$(( ))

      expr命令将它的参数作为表达式来求值,最常见用法就是进行数学运算。$(command)的结果就是执行command的 输出结果,和两个反引号的功能相同。

      对于表达式求值,一种更新的方法是使用$(( ))命令,将求值的表达式放到$(( ))中,可以很简单的完成数学运算,常见的表达式求值有:加+、减-、乘*、除/、取模%、与&、或|、等于=、不等!=、大于>、小于<等等。

      以下的例子展示这几个命令的用法:

    $ x=1
    $ x=`expr $x + 1` # 反引号是x取值为xpr $x + 1的结果
    $ x=$(expr $x + 1) # $(command)具有和反引号相同的功能
    $ x=$(($x + 1)) # 一种更新的方法是使用$(( ))命令,代替expr命令
  • set 命令和unset 命令

      set命令的作用是为shell设置参数变量。unset命令的作用是从环境中删除变量或者函数。

    #!/bin/sh
    echo the date is $(date)
    set $(date) # 将date设置为参数变量
    echo the month is $2 # 输出第二个位置参数,月份
    foo = 0
    unset foo # 删除变量foo
    exit 0
  • shift 命令

      shift命令把所有的参数变量左移一个位置,使得$2变为$1$3变为$2,依次类推,原来的$1被丢弃,而$0仍将保持不变。如果指定数值参数,可以左移相应的次数。该命令的一个主要作用是用来扫描参数,如下所示。

    #!/bin/sh
    while [ "$1" != "" ]; do
    echo "$1"
    shift
    done
    exit 0
  • trap 命令

      trap命令用于指定在接收到相应的信号后将要采取的行动,trap命令的常见形式如下:

    trap command signal
    # 第一个参数是接收到信号时将要采取的行动
    # 第二个参数是要处理的信号名
  • find 命令

      find命令是一个很有用的命令,主要用于在系统中找文件,也就是文件搜索。其基本语法格式如下:

    find [path] [options] [tests] [actions]

      其中,path部分很好理解,是要搜索的路径,可以是相对路径,也可以是绝对路径,也可以是多个路径。

      options部分是一些可用选项,主要有-depth(在查看目录本身之前先搜索目录的内容),-follow(跟随符号链接),-maxdepths N (最多搜索N层目录),-mount(或者-xdev,指不搜索其他文件系统中的目录)

      tests是测试部分,每种测试的返回结果是true或false,主要有以下几种:-atime N (文件在N天前被最后访问过),-mtime N (文件在N天前被最后修改过),-name(文件名匹配),-newer otherfile(文件比otherfile要新),-type c(文件类型是c、d、f,分别对应特殊字符文件、目录、普通文件),-user username(文件的拥有者是username)。

      注意:tests测试可以组合使用,有三个组合命令:-and,-or,-not

      actions部分是匹配之后要执行的动作,比如:-exec command(执行一条命令,最常见),-print(打印)等等。

    $ find / -name test -print
    $ find / -mount -name test -print
    $ find . -newer while2 -print
    $ find . -newer while2 -type f -print
  • grep 命令

      grep命令是通用正则表达式解析器,通俗的说,find命令在系统中找文件,grep命令在文件中找字符串,一种常用的做法是将grep作为传递给-exec的一条命令。

      grep命令的基本语法如下:

    grep [options] PATTERN [FILES]

      options是一些主要选项,常用的有-c (输出匹配行的数目)、-E(启用扩展表达式)、-h(取消每个输出行的普通前缀)、-i(忽略大小写)、-l(只列出包含匹配行的文件名)、-v(取反,搜索不匹配行)。

      PATTERN主要是一些匹配模式,常用正则表达式来表示,关于正则表达式的内容参照另一篇博文正则表达式

    grep in words.txt
    grep -c in words.txt words2.txt
    grep -c -v in words.txt words2.txt
    grep "e$" words2.txt
    grep "a[[:blank:]]" words2.txt
    grep -E [a-z]\{10\} words2.txt

总结

  Shell程序设计作为一种脚本语言,在Linux系统中有广泛的应用,本文记录了关于Shell程序设计的基础语法知识和常用命令,方便查询,熟练使用shell也需要经常实践,这对于完成一些较简单的编程任务很有帮助。另外,shell程序在Linux中海油一个可视化工具:dialog,由于不常使用,这里不再介绍。

【Shell编程】Shell基本语法的更多相关文章

  1. Shell编程的基本语法

    Shell编程 创建sh文件 touch test.sh vim test.sh 写入如下内容 #!/bin/bash a="hello" 运行 chmod +x /root/te ...

  2. [ SHELL编程 ] shell编程中数值计算方法实例

    SHELL编程中经常会涉及到数值计算,有时候对于这些计算命令使用场景容易忘记或者混淆,这里针对常用的命令做个总结.主要包括let.bc.expr.(())等. 1.let 使用格式:let 表达式,表 ...

  3. Linux Shell编程 条件判断语法

    if条件判断语句 单分支 if 条件语句 语法格式: if [条件判断式];then 程序 fi 或者 if [条件判断式] then 程序 fi 在使用单分支 if 条件查询时需要注意几点: if ...

  4. (三)Linux Shell编程——Shell常用命令(输出、判断、循环、函数、包含)

    3. 常用命令 3.1 输出 3.1.1 echo命令 echo是Shell的一个内部指令,用于在屏幕上打印出指定的字符串.命令格式: echo arg name="coding" ...

  5. Linux编程 20 shell编程(shell脚本创建,echo显示信息)

    一概述 前面19章里已经掌握了linux系统和命令行的基础知识,从本章开始继续学习shell脚本的基础知识.在大量编辑shell脚本前,先来学习下一些基本概念. 1.1    使用多个命令 Shell ...

  6. Shell编程——shell常用命令

    浏览器标签页的切换:Ctrl+Tab [终端]打开终端快捷建:Ctrl+Alt+t关闭终端快捷键:Ctrl+Shift+q打开新的终端标签页快捷键:Ctrl+Shift+t 关闭终端标签页快捷键:Ct ...

  7. shell编程 Shell script 的默认变量($0, $1...)

    Shell script 的默认变量($0, $1...) 我们知道指令可以带有选项与参数,例如 ls -la 可以察看包含隐藏文件的所有属性与权限.那么 shell script 能不能在脚本文件名 ...

  8. Shell编程——Shell中的数学运算

    在Linux Shell中进行数学运算,通常能够使用的运算符有: 简单运算: let [] (()) 高级运算: expr bc 1.let命令 let命令是bash内置命令.能够实现简单的算术以及逻 ...

  9. shell编程--基本格式,基本语法,运算符,expr,(()),$[]

    02/shell编程 Shell是用户与内核进行交互操作的一种接口,目前最流行的Shell称为bash Shell Shell也是一门编程语言."."号执行脚本时,会让脚本在调用者 ...

  10. Shell编程笔记

    Shell编程笔记与Windows下熟悉的批处理类似,也可以将一些重复性的命令操作写成一个脚本方便处理.   修改别人的脚本,运行后遇到个问题 setenv: command not found 查证 ...

随机推荐

  1. v$open_cursor的几个问题

    SQL order by SADDR desc ; SADDR SID USER ADDRESS HASH_VALUE SQL_ID SQL_TEXT -------- ---------- ---- ...

  2. 高速搞定Eclipse的语法高亮

    编辑器背景颜色 打开Preferences 选择TextEditors 语法高亮配色 这里以Javascript为例. 选择Javascript 点击右边圈出的绿色框里的选项,适当改动颜色, 高亮色參 ...

  3. UVA 12683 Odd and Even Zeroes(数学—找规律)

    Time Limit: 1000 MS In mathematics, the factorial of a positive integer number n is written as n! an ...

  4. Android中的GraphicBuffer同步机制-Fence

    Fence是一种同步机制,在Android里主要用于图形系统中GraphicBuffer的同步.那它和已有同步机制相比有什么特点呢?它主要被用来处理跨硬件的情况.尤其是CPU.GPU和HWC之间的同步 ...

  5. 工作easy,赚钱非常难

    李宗盛有首歌的歌词里写到:「工作是easy的,赚钱是困难的」. 乍一听感觉有点矛盾,工作的一个重要结果不就是赚钱么,为什么工作easy赚钱却难?但细致一想就恍然当中想表达的意思了. 工作的本质是出售劳 ...

  6. 4、angularJS过滤器

    一.过滤器的作用 过滤器用来格式化须要展示给用户的数据. 在HTML中的模板绑定符号{{ }}内通过|符号来调用过滤器. 比如.如果我们希望将字符串转换成大写能够对字符串中的每一个字符都单独进行转换操 ...

  7. Java类集-list

    Collection 子接口: ArrayList是List 接口和Collection接口的一个子类,用于实例化两种接口 package leiji; import java.util.ArrayL ...

  8. jQuery - 点击图片加边框

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. React Native - 认识与环境搭建

    01 传统开发的痛点 1.人员稀缺 2.开发成本高 3.代码复用率低 4.无法动态更新 02 React Native的优点 1.跨平台 2.性能高 3.低投入 4.支持动态更新 03 开发环境搭建 ...

  10. 倒排索引PForDelta压缩算法——基本假设和霍夫曼压缩同

    PForDelta算法 PForDelta算法最早由Heman在2005年提出,它允许同时对整个chunk数据(例128个数)进行压缩处理.基础思想是对于一个chunk的数列(例128个),认为其中占 ...