• Shell 基础


    Shell 基础

    脚本编程语言通常是解释型(interpreted)的。这类程序的执行,是由解释器(interpreter)读入程序代码,并将其转换成内部的形式,再执行。

    脚本编程语言的例子有awk、Perl、Python、Ruby与Shell。

    一个简单的例子:

    $ who
    marvin   tty7         2017-09-26 20:36 (:0)

    利用管道连接两个程序:

    $ who | wc -l
    1

    另一个例子:

    $ cat > nusers     #建立文件,使用cat复制终端的输入
    who | wc -l         #程序的内容
    ^D                  #Ctrl-D表示end-of-file
    $ chmod +x nusers  #让文件拥有执行的权限
    $ ./nusers         #执行测试
    1                   #结果输出

    当一个文件中开头的两个字符是#!时,内核会扫描该行其余的部分,看是否存在可用来执行程序的解释器的完整路径。(中间如果出现任何空白符号都会略过。)此外,内核会扫描是否有一个选项要传递给解释器。内核会以指定的选项来引用解释器再搭配命令行的其他部分。

    $ cat nusers
    #! /bin/bash
    who | wc -l

    Shell的基本元素

    命令和参数

    $ cd work ; ls -l whizprog.c
    

    以上的例子展现了UNIX命令行的原理。首先,以空白(space键或tab键)隔开命令行中各个组成部分。其次,命令名称是命令行的第一个项目。通常后面会跟着选项(option),任何额外的参数(augment)都会放在选项之后。第三,选项的开头是一个破折号(或减号),后面接着一个字母。不需要参数的选项可以合并。以两个破折号(–)来表示选项开始的用法,源自System V,不过已被纳入POSIX标准。

    分号(;)用来分隔同一行里的多条命令。Shell会依次执行这些命令。如果使用的是&符号而不是分号,则Shell将在后台执行前面的命令,这意味着,Shell不用等待该命令完成,就可以继续执行下一跳命令。

    Shell识别三种基本命令:内建命令、Shell函数和外部命令。

    变量

    Shell变量名称的开头是一个字母或下划线符号,后面可以接着任意长度的字母、数字或下划线符号。Shell变量可用来保存字符串值,所能保存的字符数没有限制。

    $ myvar=this_is_a_long_string_that_does_not_mean_mach  #分配变量值
    $ echo $myvar                                      #打印变量值
    this_is_a_long_string_that_does_not_mean_mach

    变量赋值的方式是:先写变量名,紧接着=字符,最后是新值,中间完全没有任何空格。当想取出变量的值时,要在变量的名称前面加上$字符。当所赋予的值内含空格时,需加上引号。

    1、变量的命名

    bash shell中变量的命名规则和C语言相同,必须是由英文字母、数字及下划线组成,第一个字符必须是字母或下划线,变量的长度没有限制,但英文字母区分大小写。虽然,bash shell中使用变量时不需要声明,但还是提倡对一些重要的变量进行声明、添加注释,以便阅读和维护。声明或创建一个变量之后,它的作用域是当前shell,子shell无法获取父shell中定义的变量,除非该变量时环境变量。

    2、设定变量

    在bash shell中要设置某个变量的值是很容易的,只需要按照:

    变量名称=值

    的方式即可改变某个变量的值,需要注意的是等号的两边是不能有空格的,若值中含有空格的话,需要用引号括起来。

    3、获取变量值

    要获取某个变量的值只需要在该变量的名称前面加上{}将变量括起来即可。

    # echo $PATH
    # echo ${PATH}

    4、取消与清空变量

    当你不再需要某个变量时,你可能想取消该变量,即将该变量从当前名字空间中删除并释放该变量所占用的内存。在bash shell中可以用unset命令来取消某个变量。用法如下:

    unset 变量名称 或 unset -v 变量名称

    -v表示取消变量,unset除了可以用来取消变量外,还可以用来取消函数,用unset来取消函数时,用法如下:

    unset -f 函数名称

    使用unset以后,变量就不复存在了,这可能并不是你想要的,你可能只是想将清除该变量中的值,使其为null,即清空变量,清空变量的操作如下:

    变量名称=

    5、环境变量

    只有当一个变量成为环境变量时,它才能为子shell所用,为了使一个变量成为环境变量,需要使用export命令,具体如下:

    变量名称="xxxx"
    export 变量名称 
    或
    export 变量名称="xxxx"

    除了使用export之后,还可以在声明的时候就将变量指定为环境变量,如下:

    declare -x 变量名称

    6、bash的内置变量

    除了环境变量和用户自定义的变量之外,bash shell中还会用到很多的内置变量,下面介绍一些常用的内置变量。

    BASH– bash的完整路径,通常是/bin/bash

    BASH_VERSION– bash的版本

    BASH_ENV– 在非交互模式下,会先检查$BASH_ENV是否有指定的启动文件,如果有则先执行它

    ENV– 与BASH_ENV类似,不过是在POSIX模式下,会先检查$ENV是否有指定的启动文件,如果有则先执行它

    CDPATH– cd命令的搜索路径

    PATH – 命令的搜索路径

    EUID– 有效的用户id

    FUNCNAME– 在函数执行期间,即为函数的自身的名称

    HOSTNAME– 主机名

    HOSTTYPE– 主机类型,如i386

    OSTYPE– 执行bash的操作系统类型,如linux-gnu

    HOME– 用户主目录

    IFS– 默认的字段分隔符

    OPTARG– 使用getopts处理选项时,取得的选项的参数

    OPTIND– 使用getopts处理选项时,选项的索引值

    OPTERR– 若将OPTERR设置为1,则getopts发生错误,输出错误信息

    $1~$n – 位置参数,即传入程序或函数的参数,12为第二个参数,其他类推

    $* – 所有的位置参数,并将其看成一个字符串,如”test.sh abc 123“,则$*为”abc 123“

    $@ – 所有的位置参数,并将其看成一个字符串数组,如”test.sh abc 123“,则$*为”abc 123“

    $# – 位置参数的个数

    $? – 上一条命令执行结束后的返回值

    $$ – 当前bash shell的进程号

    $! – 上一个后台程序的进程号

    7、调整变量的属性

    declare命令不仅可以用来声明变量,还可以用来调整变量的属性,具体用法如下:

    -p 显示变量的属性

    -a 变量是一个数组

    -i 变量是一个整数

    -r 变量为只读的

    -x 变量为环境变量

    简单的echo输出

    原始的echo命令只会将参数打印到标准输出,参数之间以一个空格隔开,并以换行符号(newline)结尾。

    echo转义序列

    printf输出

    printf命令的完整语法分为两部分:

    printf format-stirng [arguments ... ]

    第一部分是一个字符串,用来描述输出的排列方式,最好为此字符串加上引号。此字符串包含了按字面显示的字符(characters to be printed literally)以及格式声明(format specifications),后者是特殊的占位符(placeholders),用来描述如何显示相应的参数(argument)。

    第二部分是与格式声明相对应的参数列表(argument list)。格式声明分成两部分:百分比符号(%)和指示符号(specifier)。最常用的格式指示符(format specifier)有两个,%s用于字符串,%d用于十进制整数。

    $ printf "The first program always prints '%s, %s'
    " Hello world
    The first program always prints 'Hello, world'

    bash shell启动配置文件

    Bash有4种运行模式,分别是:

    1)交互模式:即bash在终端中等待你输入一条命令,然后对这条命令进行解释执行,最后输出结果的执行过程;如当你想了解当前目录下有哪些文件时,你可以打开一个终端,输入ls命令即可。

    2)非交互模式:即通过执行shell脚本的方式使用bash,你可以将你经常要用到的一些命令写出脚本,然后每次调用该shell脚本,这样就可以省去每次都输入同样的命令的麻烦。此外,通过shell脚本可以完成很多复杂繁琐的事情,大大的提高自动化的程度。

    3)POSIX模式:即以“bash –posix”方式来运行bash。在POSIX模式下,bash与POSIX标准兼容,此时bash会检查ENV变量的内容,若有定义,就执行该变量所定义的配置文件的内容。

    4)受限模式:即以“bash -r”方式来运行bash,在该模式下,bash的功能受到许多限制,如:不能使用cd命令、不能设定或取消环境变量、不能做输入输出的重定向等操作。

    在不同的模式下,bash调用不同的启动配置文件:

    • 登录(login):首先执行/etc/profile,接着bash检查用户主目录的配置文件,依次检查.bash_profile、.bash_login、.profile等配置文件是否存在,如果存在则加载其中的配置。

    • 注销(logout):注销时,bash检查主目录是否有.bash_logout,如有,则读取并执行它。

    • 执行新shell:执行新shell是指登录以后,创建新的shell,这时根据bash的执行模式会加载不同的配置文件:
      • 交互模式:在该模式下,bash首先会读取并执行/etc/bash.bashrc,然后读取并执行.bashrc
      • 非交互模式:在非交互模式下,它会检查BASH_ENV变量的内容,若该变量有定义,则执行该变量所定义的启动文件的内容

    基本的I/O重定向

    • < 改变标准输入

      • program < file可将program的标准输入改为file:

      • tr -d '
        ' < dos-file.txt ...
    • >改变标准输出

      • program > file可将program的标准输出修改为file:

      • tr -d '
        ' < dos-file.txt > UNIX-file.txt
      • 这条命令会先以trdos-file.txt里的ASCII carriage-return(回车)删除,再将转换成的数据输出到UNIX-file.txtdos-file.txt里的原始数据不会有变化。

      • >重定向符(redirector)在目的文件不存在时,会新建一个。然而,如果目的文件已存在,他就会覆盖掉,原本的数据都会丢失。

    • >>附加到文件

      • program >> file可将program的标准输出附加到file的结尾处。

      • 如同>,目的文件不存在时,会新建一个。然而,如果目的文件已存在,它不会直接覆盖掉文件,而是将程序产生的数据附加到文件结尾处。

      • for f in dos-file*.txt
        do
        tr -d '
        ' < $f >> big-UNIX-file.txt
        done
    • |建立管道

      • program1 | program2可将program1的标准输出修改为program2的标准输入。

      • 虽然<>可将输入与输出连接到文件,不过管道(pipeline)可以把两个以上执行中的程序衔接在一起。第一个程序的标准输出变为第二个程序的标准输入。这样做可以加快程序的执行速度。

      • tr -d '
        ' < dos-file.txt | sort > UNIX-file.txt
        
        # 这条管道会先删除输入文件内的回车字符,在完成数据的排序后,将结果输出到目的文件
        

    tr命令

    • 语法

      • shell
        tr [ options ] source-char-list replace-char-list
    • 用途

      • 转换字符。
    • 常用选项

      • -c

      • source-char-list的反义,tr要转换的字符,变成未列在source-char-list中的字符。

      • -C

      • -c相似,但所处理的是字符,而非二进制的字节值。

      • 根据POSIX标准的定义,-c处理的是二进制字节值,而-C处理的是现行locale所定义的字符。

      • -d

      • 自标准输入删除source-char-list里所列的字符。

      • -s

      • 浓缩重复的字符。如果标准输入中连续重复出现source-char-list里所列的字符,则将其浓缩成一个。

    • 行为模式

      • 如同过滤器:自标准输入读取字符,再将结果写到标准输出。任何输入字符只要出现在source-char-lsit中,就会置换成replace-char-list里相应的字符。

    特殊文件

    /dev/null

    第一个文件/dev/null就是熟知的位桶(bit bucket)。传送到此文件的数据都会被系统过滤掉。也就是说,当程序将数据写到此处文件时,会认为它已经成功完成写入数据的操作,但实际上什么事都没做。

    例如。测试一个文件是否包含某个模式(pattern)

    if grep pattern myfile >> /dev/null
    then
        ...#找到模式时
    else
        ...#找不到模式时
    fi

    相应地,读取dev ull会立即返回文件结束符号(end-of-file)。

    /dev/tty

    另一个特殊文件为/dev/tty。当程序打开此文件时,UNIX会自动将它重定向到一个终端[一个实体的控制台(console)或串行端口(serial port),也可能是一个通过网络与窗口登录的伪终端(pseudo terminal)]再与程序结合。

    这在程序必须读取人工输入时(例如密码)特别有用。例如:

    printf "enter new password: "   #提示输入
    stty -echo                      #关闭自动打印输入字符的功能
    read pass < /dev/tty            #读取密码
    printf "enter again: "
    read pass2 < /dev/tty
    stty echo                       #打开自动打印输入字符的功能

    stty(set tty)命令用来控制终端(或窗口)的各种设置。

    基本命令查找

    Shell会沿着查找路径$PATH来寻找命令。$path是一个以冒号分隔的目录列表,可以在列表所指定的目录下找到所要执行的命令。所找到的命令可能是编译后的可执行文件。也可能是Shell脚本。

    默认路径因系统而异,不过至少包含/bin/usr/bin,也许还包含存放X Windows程序的/usr/X11R6/bin。以及供本地系统管理人员安装程序的/usr/local/bin,例如:

    $ echo $PATH
    /home/marvin/bin:/home/marvin/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

    如果要编写自己的脚本,最好准备自己的bin目录来存放它们,并且让Shell能够自动找到它们。例如:

    $ cd           #切换到home目录
    $ mkdir bin
    $ mv nusers bin
    $ PATH=$PATH:$HOME/bin    #将个人的bin目录附加到PATH

    要让修改永久生效,在.profile文件中把你的bin目录加入$PATH,而每次登陆时Shell都会读取.profile文件。

    $PATH里的空项目(empty component)表示当前目录。例如:

    PATH=:/bin/:/usr/bin:/usr/local/bin     #先找当前目录
    PATH=/bin/:/usr/bin:/usr/local/bin:     #最后找当前目录
    PATH=:/bin/:/usr/bin::/usr/local/bin        #当前目录居中

    最好的做法是在$PATH中使用点号(dot)

    访问Shell脚本的参数

    1、位置参数

    由系统提供的参数称为位置参数。位置参数的值可以用NN11. 类似C语言中的数组,Linux会把输入的命令字符串分段并给每段进行标号,标号从0开始。第0号为程序名字,从1开始就表示传递给程序的参数。如01表示传递给程序的第一个参数,以此类推。

    所谓位置参数(positional parameters)指的是Shell脚本的命令行参数(command-line arguments)。在Shell函数里,它们同时也可以是函数的参数。例如:

    echo first arg is $1
    echo tenth arg is $(10)
    $ cat > finduser   #建立新文件
    #! /bin/bash
    #finduser 查看第一个参数所指定的用户是否登录
    
    who | grep $1
    ^D
    $ chmod +x finduser
    $ $ ./finduser marvin
    marvin   tty2         2017-10-08 14:39 (:1)

    2、内部参数

    上述过程中的01则可有可无。和$0一样的内部变量还有以下几个。

    $# – 传递给程序的总的参数数目

    $? – 上一个代码或者CentOS shell程序在shell中退出的情况,如果正常退出则返回0,反之为非0值。

    $* – 传递给程序的所有参数组成的字符串。

    @*类似,只是在使用双引号时有所不同。

    字符串比较

    作用:测试字符串是否相等、长度是否为零,字符串是否为NULL(注:bash区分零长度字符串和空字符串)

    常用的字符穿操作符有:

    = 比较两个字符串是否相同,同则为“是”

    != 比较两个字符串是否相同,不同则为“是”

    -n 比较字符串长度是否大于零,如果大于零则为“是”

    -z 比较字符串的穿度是否等于零,如果等于则为“是”

    数字比较

    这里区别于其他编程语言,shell中不使用>、<、>=类似的符号来表达大小的比较,而是用整数式来表示这些。

    -eq 相等

    -ge 大于等于

    -le 小于等于

    -ne 不等于

    -gt 大于

    -lt 小于

    逻辑操作

    ! 反:与一个逻辑值相反的逻辑值

    -a 与:两个逻辑值为“是”返回值才为“是”,反之为“否”

    -o 或:两个逻辑值有一个为“是”,返回值就为“是”

    文件操作

    文件测试表达式通常是为了测试文件的信息,一般由脚本来决定文件是否应该备份、复制或删除。由于test关于文件的操作符有很多,我们只列举一些常用的。

    -d 对象存在且为目录返回值为“是”

    -f 对象存在且为文件返回值为“是”

    -L 对象存在且为符号连接返回值为“是”

    -r 对象存在且可读则返回值为“是”

    -s 对象存在且长度非零则返回值为“是”

    -w 对象存在且可写则返回值为“是”

    -x 对象存在且可执行则返回值为“是”

    执行跟踪

    将执行跟踪(execution tracing)的功能打开,这会使得Shell显示每个被执行到的额命令,并在前面加上”+ “:一个加号后面跟着一个空格。(可以通过给Shell变量PS4赋一个新值来改变打印方式)

    例如:

    $ sh -x nusers #开启执行跟踪功能
    + who   #被跟踪的命令
    + wc -l
    1       #实际的输出

    也可以在脚本里,用set -x命令将执行跟踪功能打开,然后set +x命令关闭它。

    国际化和本地化

    internationalizatioin

    localization

  • 相关阅读:
    python分析log
    单词长度统计,字符数量统计直方图
    单词计数
    字符替换
    HP Mobile Center 1.01 Related System Requirements
    字符统计
    文件复制
    C语言,不是从hello world开始
    最近
    echarts Map(地图) 不同颜色区块显示
  • 原文地址:https://www.cnblogs.com/born2run/p/9581392.html
Copyright © 2020-2023  润新知