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

原文地址:https://www.cnblogs.com/born2run/p/9581392.html