当前位置:   article > 正文

Shell常用命令_etc/shells

etc/shells

SHELL

常见的Shell

查看shell

当前 Linux 系统可用的 Shell 都记录在/etc/shells文件中。/etc/shells是一个纯文本文件

$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在现代的 Linux 上,sh 已经被 bash 代替,/bin/sh往往是指向/bin/bash的符号链接

如果你希望查看当前 Linux 的默认 Shell,那么可以输出 SHELL 环境变量:

$ echo $SHELL
/bin/bash
  • 1
  • 2

shell提示符

对于普通用户,Base shell 默认的提示符是美元符号$;对于超级用户(root 用户),Bash Shell 默认的提示符是井号#。该符号表示 Shell 等待输入命令

Shell 通过PS1PS2两个环境变量来控制提示符格式:

  • PS1 控制最外层命令行的提示符格式。
  • PS2 控制第二层命令行的提示符格式。

要显示提示符的当前格式,可以使用 echo 输出 PS1 和 PS2:

[mozhiyan@localhost ~]$ echo $PS1
[\u@\h \W]\$
[mozhiyan@localhost ~]$ echo $PS2
>
  • 1
  • 2
  • 3
  • 4

Shell 使用以\为前导的特殊字符来表示命令提示符中包含的要素,这使得 PS1 和 PS2 的格式看起来可能有点奇怪。下表展示了可以在 PS1 和 PS2 中使用的特殊字符。

字符描述
\a铃声字符
\d格式为“日 月 年”的日期
\eASCII转义字符
\h本地主机名
\H完全合格的限定域主机名
\jshell当前管理的作业数
\1shell终端设备名的基本名称
\nASCII换行字符
\rASCII回车
\sshell的名称
\t格式为“小时:分钟:秒”的24小时制的当前时间
\T格式为“小时:分钟:秒”的12小时制的当前时间
@格式为am/pm的12小时制的当前时间
\u当前用户的用户名
\vbash shell的版本
\Vbash shell的发布级别
\w当前工作目录
\W当前工作目录的基本名称
!该命令的bash shell历史数
#该命令的命令数量
$如果是普通用户,则为美元符号$;如果超级用户(root 用户),则为井号#
\nnn对应于八进制值 nnn 的字符
\斜杠
[控制码序列的开头
]控制码序列的结尾

注意,所有的特殊字符均以反斜杠\开头,目的是与普通字符区分开来。您可以在命令提示符中使用以上任何特殊字符的组合。我们可以通过修改 PS1 变量来修改提示符格式,例如:

[mozhiyan@localhost ~]$ PS1="[\t][\u]\$ "[17:27:34][mozhiyan]$ 
  • 1

新的 Shell 提示符现在可以显示当前的时间和用户名。不过这个新定义的 PS1 变量只在当前 Shell 会话期间有效,再次启动 Shell 时将重新使用默认的提示符格式

First Shell脚本

打开文本编辑器,新建一个文本文件,并命名为 test.sh。

扩展名sh代表 shell,扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用php好了

在 test.sh 中输入代码:

#!/bin/bash
echo "Hello World !"  #这是一条语句
  • 1
  • 2

第 1 行的#!是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell;后面的/bin/bash就是指明了解释器的具体位置。

第 2 行的 echo 命令用于向标准输出文件(Standard Output,stdout,一般就是指终端)输出文本。在.sh文件中使用命令与在终端直接输入命令的效果是一样的。

第 2 行的#及其后面的内容是注释。Shell 脚本中所有以#开头的都是注释(当然以#!开头的除外)。写脚本的时候,多写注释是非常有必要的,以方便其他人能看懂你的脚本,也方便后期自己维护时看懂自己的脚本——实际上,即便是自己写的脚本,在经过一段时间后也很容易忘记。

下面给出了一段稍微复杂的 Shell 脚本:

#!/bin/bash
# Copyright (c) http://c.biancheng.net/shell/
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"
  • 1
  • 2
  • 3
  • 4
  • 5

第 5 行中表示从终端读取用户输入的数据,并赋值给 PERSON 变量。read 命令用来从标准输入文件(Standard Input,stdin,一般就是指终端)读取用户输入的数据。

第 6 行表示输出变量 PERSON 的内容。注意在变量名前边要加上$,否则变量名会作为字符串的一部分处理。

执行shell脚本方法

作为可执行程序

Shell 脚本也是一种解释执行的程序,可以在终端直接调用(需要使用 chmod 命令给 Shell 脚本加上执行权限),如下所示:

$ cd demo  #切换到 test.sh 所在的目录
$ chmod +x ./test.sh  #使脚本具有执行权限
$ ./test.sh  #执行脚本
  • 1
  • 2
  • 3

第 2 行中,chmod +x表示给 test.sh 增加执行权限。

第 3 行中,./表示当前目录,整条命令的意思是执行当前目录下的 test.sh 脚本。如果不写./,Linux会到系统路径(由 PATH 环境变量指定)下查找 test.sh,而系统路径下显然不存在这个脚本,所以会执行失败。

通过这种方式运行脚本,第一行一定要写对,好让系统查找到正确的解释器。

1) 使用点号.

点号用于执行某个脚本,甚至脚本没有可执行权限也可以运行。有时候在测试运行某个脚本时可能并不想为此修改脚本权限,这时候就可以使用.来运行脚本,非常方便。

如果没有运行权限的话,用./执行就会有报错,但是若在其前面使用点号来执行就不会报错

$ . ./test.sh  #注意 两个 . 之间有空格
  • 1
2) 使用 source 命令

与点号类似,source 命令也可读取并在当前环境中执行脚本,同时还可返回脚本中最后一个命令的返回状态;如果没有返回值则返回 0,代表执行成功;如果未找到指定的脚本则返回 false。

$ source test.sh
  • 1

作为解释器参数

这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:

$ /bin/bash test.sh
http://c.biancheng.net/shell/
  • 1
  • 2

这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用

安装Bash Shell

安装步骤

定义变量

三种声明方式

variable=value
variable='value'
variable="value"
  • 1
  • 2
  • 3

注意,赋值号=的周围不能有空格,这可能和你熟悉的大部分编程语言都不一样

三者的区别
  • 如果 value 不包含任何空白符(例如空格、Tab 缩进等),那么可以不使用引号
  • 以单引号' '包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。
  • 以双引号" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。

两种使用方式

echo $variable
echo ${variable}
#下面这种情况,需要加{},否则解释器就会把 $skillScript 当成一个变量(其值为空)
echo "I am good at ${skill}Script"
  • 1
  • 2
  • 3
  • 4

加花括号是为了帮助解释器识别变量的边界,推荐给所有变量加上花括号{}

只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变

#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl
#下面这一行会报错:zsh: read-only variable: myUrl
myUrl="http://see.xidian.edu.cn/cpp/danpianji/"
  • 1
  • 2
  • 3
  • 4
  • 5

删除变量

使用 unset命令可以删除变量。语法:

unset variable_name
  • 1

变量被删除后不能再次使用;unset 命令不能删除只读变量

变量作用域

一共三种作用域

全局变量

所谓全局变量,就是指变量在当前的整个 Shell 会话中都有效。每个 Shell 会话都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就是全局变量

需要强调的是,全局变量的作用范围是当前的 Shell 会话,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 会话,打开多个 Shell 窗口就创建了多个 Shell 会话,每个 Shell 会话都是独立的进程,拥有不同的进程 ID。在一个 Shell 会话中,可以执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效

局部变量

Shell 也支持自定义函数,但是 Shell 函数和 C/C++Java 等其他编程语言函数的一个不同点就是:在 Shell 函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果

要想变量的作用域仅限于函数内部,那么可以在定义时加上local命令,此时该变量就成了局部变量

#!/bin/bash
#定义函数
function func(){
    local a=99
}
#调用函数
func
#输出函数内部的变量
echo $a
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

输出结果为空,表明变量 a 在函数外部无效,是一个局部变量。

Shell 变量的这个特性和 JavaScript 中的变量是类似的。在 JavaScript 函数内部定义的变量,默认也是全局变量,只有加上var关键字,它才会变成局部变量

环境变量

使用export命令将它导出,它就在所有的子 Shell 中也有效了

环境变量被创建时所处的 Shell 被称为父 Shell,如果在父 Shell 中再创建一个 Shell,则该 Shell 被称作子 Shell。当子 Shell 产生时,它会继承父 Shell 的环境变量为自己所用,所以说环境变量可从父 Shell 传给子 Shell。不难理解,环境变量还可以传递给孙 Shell。

注意,环境变量只能向下传递而不能向上传递,即“传子不传父”。

在一个 Shell 中创建子 Shell 最简单的方式是运行 bash 命令

通过exit命令可以一层一层地退出 Shell

export a这种形式是在定义变量 a 以后再将它导出为环境变量,如果想在定义的同时导出为环境变量,可以写作export a=22

如果想让环境变量在所有 Shell 中都有效,并且能够永久保存,在关闭 Shell 后也不丢失,那么就需要把环境变量写入启动文件

位置参数(命令行参数)

运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

同样,在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用$n的形式接收,例如,$1 表示第一个参数,$2表示第二个参数,依次类推。

这种通过$n的形式来接收的参数,在 Shell 中称为位置参数

  • 给脚本文件传递位置参数

    #!/bin/bash
    echo "Language: $1"
    echo "URL: $2"
    
    • 1
    • 2
    • 3
    $ . ./a.sh Shell http://c.biancheng.net/shell/
    
    • 1
  • 给函数传递位置参数

#!/bin/bash
#定义函数
function func(){
    echo "Language: $1"
    echo "URL: $2"
}
#调用函数
func C++ http://c.biancheng.net/cplus/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

特殊变量

变量含义
$0当前脚本的文件名。
$n(n≥1)传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是 $2
$#传递给脚本或函数的参数个数。${#str} 可以获取str字符串长度
$*传递给脚本或函数的所有参数。
$@传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同,我们将在《Shell ∗ 和 *和 @的区别》一节中详细讲解。
$?上个命令的退出状态,或函数的返回值,我们将在《Shell $?》一节中详细讲解。
$$当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。

$*$@的区别

当 $* 和 $@ 不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。但是当它们被双引号" "包含时,就会有区别了:

  • "$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。
  • "$@"仍然将每个参数都看作一份数据,彼此之间是独立的。 注:可以分割用于for循环

$? :获取函数返回值或上一个命令的退出状态

  • 获取上一个命令的退出状态

    a.sh

    #!/bin/bash
    if [ $1 == 100 ]
    then
       return 0  #参数正确,返回0
    else
       return 1  #参数错误,返回1
    fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    b.sh

    #!/bin/bash
    echo $?
    
    • 1
    • 2

    结果:

    $ . ./a.sh 100
    $ . ./b.sh
    0
    
    • 1
    • 2
    • 3
  • 获取函数返回值

    test.sh

    #!/bin/bash
    #得到两个数相加的和
    function add(){
        return `expr $1 + $2`
    }
    add 23 50  #调用函数
    echo $?  #获取函数返回值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:

    $ . ./test.sh
    73
    
    • 1
    • 2

字符串截取

指定位置截取

  • 从左向右

    #${string: start :length}
    #string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),length 是要截取的长度(省略的话表示直到字符串的末尾)
    url="c.biancheng.net"
    echo ${url: 2: 9}
    echo ${url: 2}  #省略 length,截取到字符串末尾
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 从右向左

    从右边开始计数时,起始数字是 1。不管从哪边开始计数,截取方向都是从左到右

    #${string: 0-start :length}
    url="c.biancheng.net"
    echo ${url: 0-13: 9}
    #上面的结果为biancheng。从右边数,b是第 13 个字符
    url="c.biancheng.net"
    echo ${url: 0-13}  #省略 length,直接截取到字符串末尾
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

从指定字符(子字符串)开始截取

  • 使用 # 号截取右边字符
#使用#号可以截取指定字符(或者子字符串)右边的所有字符
${string#*chars}
#示例
url="http://c.biancheng.net/index.html"
echo ${url#*:}
#结果为//c.biancheng.net/index.html

#如果希望直到最后一个指定字符(子字符串)再匹配结束,那么可以使用##
${string##*chars}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),*是通配符的一种,表示任意长度的字符串。*chars连起来使用的意思是:忽略左边的所有字符,直到遇见 chars(chars 不会被截取

  • 使用 % 截取左边字符
    #注意*的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。其他方面%和#的用法相同
    ${string%chars*}
    
    • 1
    • 2
  • 汇总

    格式说明
    ${string: start :length}从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。
    ${string: start}从 string 字符串的左边第 start 个字符开始截取,直到最后。
    ${string: 0-start :length}从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
    ${string: 0-start}从 string 字符串的右边第 start 个字符开始截取,直到最后。
    ${string#*chars}从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
    ${string##*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
    ${string%*chars}从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
    ${string%%*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。

数组

数组定义

Shell 是弱类型的,它并不要求所有数组元素的类型必须相同
Shell 数组元素的下标也是从 0 开始计数

array_name=(ele1  ele2  ele3 ... elen)
#下面的ages只给第 3、5、10 个元素赋值,所以数组长度是 3
ages=([3]=24 [5]=19 [10]=12)
  • 1
  • 2
  • 3

获取数组元素

#其中,array_name 是数组名,index 是下标
${array_name[index]}
  • 1
  • 2

使用@*可以获取数组中的所有元素

${nums[*]}
${nums[@]}
  • 1
  • 2

获取数组长度

利用@*,可以将数组扩展成列表,然后使用#来获取数组元素的个数

${#array_name[@]}
${#array_name[*]}
  • 1
  • 2

如果某个元素是字符串,还可以通过指定下标的方式获得该元素的长度

${#arr[2]}
  • 1

数组拼接

拼接数组的思路是:先利用@*,将数组扩展成列表,然后再合并到一起

array_new=(${array1[@]}  ${array2[@]})
array_new=(${array1[*]}  ${array2[*]})
  • 1
  • 2

删除

#删除某个元素
unset array_name[index]
#删除整个数组
unset array_name
#array_name 表示数组名,index 表示数组下标
  • 1
  • 2
  • 3
  • 4
  • 5

内建命令alias

#查看当前存在的别名列表
$ alias
#添加别名,当前shell有效
$ alias myShutdown='shutdown -h now'
#为了确保永远生效,可以将该别名手动写入到用户主目录中的.bashrc

#删除所有别名,当前shell有效
$ unalias -a
#删除指定别名,当前shell有效
$ unalias 别名名字
#要想永久删除在.bashrc文件中定义的别名,只能进入该文件手动删除
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

内建命令echo

echo 命令输出结束后默认会换行,如果不希望换行,可以加上-n参数

name="Tom"
height=175
weight=62
echo -n "${name} is years old, "
echo -n "${height}cm in height "
echo "and ${weight}kg in weight."
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

默认情况下,echo 不会解析以反斜杠\开头的转义字符。比如,\n表示换行,echo 默认会将它作为普通字符

我们可以添加-e参数来让 echo 命令解析转义字符

[root@localhost ~]# echo -e "hello \nworld"
hello
world
  • 1
  • 2
  • 3

有了-e参数,我们也可以使用转义字符\c来强制 echo 命令不换行了

#!/bin/bash
name="Tom"
weight=62
echo -e "${name}  years old, \c"
echo "and ${weight}kg in weight."
  • 1
  • 2
  • 3
  • 4
  • 5

内建命令exit

  • 如果在终端中直接运行 exit 命令,会退出当前登录的 Shell,并关闭终端;

  • 如果在 Shell 脚本中出现 exit 命令,会停止执行后边的所有代码,立即退出 Shell 脚本

  • exit 命令可以接受的参数是一个状态值 n,代表退出时的状态。如果不指定,默认状态值是 0

    #!/bin/bash
    echo "befor exit"
    exit 8
    echo "after exit"
    
    • 1
    • 2
    • 3
    • 4

    我们可以紧接着使用 $?来获取 demo.sh 的退出状态

    [root@localhost ~]# echo $?
    8
    
    • 1
    • 2

内建命令ulimit

默认情况下 Linux 系统的各个资源都做了软硬限制,其中硬限制的作用是控制软限制(换言之,软限制不能高于硬限制)。使用ulimit -a可以查看当前系统的软限制,使用命令ulimit -a –H可查看系统的硬限制

[root@localhost ~]# ulimit -a
#core文件大小,单位是block,默认为0
core file size          (blocks, -c) 0
#数据段大小,单位是kbyte,默认不做限制
data seg size           (kbytes, -d) unlimited
#调度优先级,默认为0
scheduling priority             (-e) 0
#创建文件的大小,单位是block,默认不做限制
file size               (blocks, -f) unlimited
#挂起的信号数量,默认是8192
pending signals                 (-i) 8192
#最大锁定内存的值,单位是kbyte,默认是32
max locked memory       (kbytes, -l) 32
#最大可用的常驻内存值,单位是kbyte,默认不做限制
max memory size         (kbytes, -m) unlimited
#最大打开的文件数,默认是1024
open files                      (-n) 1024
#管道最大缓冲区的值
pipe size            (512 bytes, -p) 8
#消息队列的最大值,单位是byte
POSIX message queues     (bytes, -q) 819200
#程序的实时性优先级,默认为0
real-time priority              (-r) 0
#栈大小,单位是kbyte
stack size              (kbytes, -s) 10240
#最大cpu占用时间,默认不做限制
cpu time               (seconds, -t) unlimited
#用户最大进程数,默认是8192
max user processes              (-u) 8192
#最大虚拟内存,单位是kbyte,默认不做限制
virtual memory          (kbytes, -v) unlimited
#文件锁,默认不做限制
file locks                      (-x) unlimited
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

每一行中都包含了相应的改变该项设置的参数,以最大可以打开的文件数为例(open files 默认是 1024),想要增大至 4096 则按照如下命令设置(可参照此方法调整其他参数)

#设置最大打开的文件数
#该命令会同时设置硬限制和软限制
[root@localhost ~]# ulimit -n 4096
#使用-S参数单独设置软限制
#[root@localhost ~]# ulimit -S -n 4096
#使用-H参数单独设置硬限制
#[root@localhost ~]# ulimit -H -n 4096
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用 ulimit 直接调整参数,只会在当前运行时生效,一旦系统重启,所有调整过的参数就会变回系统默认值。所以建议将所有的改动放在 ulimit 的系统配置文件中

[root@localhost ~]# cat /etc/security/limits.conf
# /etc/security/limits.conf
#该文件是ulimit的配置文件,任何对系统的ulimit的修改都应该写入该文件
#请将所有的设置写到该文件的最后
#Each line describes a limit for a user in the form:
#配置应该写成下面这行的格式,即每个配置占用1行,每行4列
#每列分别是<domain> <type> <item> <value>
#<domain>        <type>  <item>  <value>
#
#其中:
#<domain>可以取的值如下:
#       - 一个用户名
#       - 一个组名,组名前面用@符号
#       - 通配符*
#       - 通配符%
#Where:
#<domain> can be:
#        - an user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#
#<type>只有以下两个可用值:
#       - soft用于设置软限制
#       - hard用于设置硬限制
#<type> can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
#<item>的值可以是以下任意一种:
#        - core - core文件大小的限制 (KB)
#        - data - 最大数据段限制 (KB)
#        - fsize - 最大文件大小 (KB)
#        - memlock - 最大锁定的内存大小 (KB)
#        - nofile - 最大打开文件数
#        - rss - 最大常驻内存值 (KB)
#        - stack - 最大栈空间大小 (KB)
#        - cpu - 最大CPU使用时间 (MIN)
#        - nproc - 最大进程数
#        - as - 虚拟地址空间
#        - maxlogins - 某用户的最大登录数
#        - maxsyslogins - 系统用户最大登录数
#        - priority - 用户进程的运行优先级
#        - locks – 用户最大可以锁定文件的数量
#        - sigpending - 最大挂起的信号量数
#        - msgqueue - POSIX信号队列使用的最大内存值 (bytes)
#        - nice - 最大nice值
#        - rtprio - 最大实时优先级
#
#<item> can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open files
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to
#        - rtprio - max realtime priority
#
#<domain>      <type>  <item>         <value>
#
#以下是使用样例,请参照配置
#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

内建命令declare

declare [+/-] [aAfFgilprtux] [变量名=变量值]
  • 1

其中,-表示设置属性,+表示取消属性,aAfFgilprtux都是具体的选项,它们的含义如下表所示

选项含义
-f [name]列出之前由用户在脚本中定义的函数名称和函数体。
-F [name]仅列出自定义函数名称。
-g name在 Shell 函数内部创建全局变量。
-p [name]显示指定变量的属性和值。
-a name声明变量为普通数组。
-A name声明变量为关联数组(支持索引下标为字符串)。
-i name将变量定义为整数型。
-r name[=value]将变量定义为只读(不可修改和删除),等价于 readonly name。
-x name[=value]将变量设置为环境变量,等价于 export name[=value]。

【实例1】将变量声明为整数并进行计算

#!/bin/bash
declare -i m n ret  #将多个变量声明为整数
m=10
n=30
ret=$m+$n
echo $ret
#运行结果:40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意:除了将参与运算的变量定义为整数,还得将承载结果的变量定义为整数,而且只能用整数类型的变量来承载运算结果,不能直接使用 echo 输出。

和 (())、let、$[] 不同,declare -i的功能非常有限,仅支持最基本的数学运算(加减乘除和取余),不支持逻辑运算(比较运算、与运算、或运算、非运算),所以在实际开发中很少使用

【实例2】将变量定义为只读变量

[c.biancheng.net]$ declare -r n=10
[c.biancheng.net]$ n=20
-bash: n: readonly variable
[c.biancheng.net]$ echo $n
10
  • 1
  • 2
  • 3
  • 4
  • 5

【实例3】显示变量的属性和值

[c.biancheng.net]$ declare -r n=10
[c.biancheng.net]$ declare -p n
declare -r n="10"
  • 1
  • 2
  • 3

命令替换:将命令输出赋给变量

Shell 中有两种方式可以完成命令替换,一种是反引号,一种是$()

var_name=`command`
var_name=$(command)
  • 1
  • 2

如果被替换的命令的输出内容包括多行(也即有换行符),或者含有多个连续的空白符,那么在输出变量时应该将变量用双引号包围,否则系统会使用默认的空白符来填充,这会导致换行无效,以及连续的空白符被压缩成一个.所以,为了防止出现格式混乱的情况,建议在输出变量时加上双引号

反引号和 $()区别

  • $() 支持嵌套

    [root@localhost ~]# Fir_File_Lines=$(wc -l $(ls | sed -n '1p'))
    [root@localhost ~]# echo "$Fir_File_Lines"
    36 anaconda-ks.cfg
    
    • 1
    • 2
    • 3
  • $() 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中使用

数学计算

常见的 Shell 算术运算符

算术运算符说明/含义
+、-加法(或正号)、减法(或负号)
*、/、%乘法、除法、取余(取模)
**幂运算
++、–自增和自减,可以放在变量的前面也可以放在变量的后面
!、&&、||逻辑非(取反)、逻辑与(and)、逻辑或(or)
<、<=、>、>=比较符号(小于、小于等于、大于、大于等于)
==、!=、=比较符号(相等、不相等;对于字符串,= 也可以表示相当于)
<<、>>向左移位、向右移位
~、|、 &、^按位取反、按位或、按位与、按位异或
=、+=、-=、*=、/=、%=赋值运算符,例如 a+=1 相当于 a=a+1,a-=1 相当于 a=a-1

Shell 中常用的数学计算命令如下表

运算操作符/运算命令说明
(( ))用于整数运算,效率很高,推荐使用
let用于整数运算,和 (()) 类似。
[$]用于整数运算,不如 (()) 灵活。
expr可用于整数运算,也可以处理字符串。比较麻烦,需要注意各种细节,不推荐使用。
bcLinux下的一个计算器程序,可以处理整数和小数。Shell 本身只支持整数运算,想计算小数就得使用 bc 这个外部的计算器。
declare -i将变量定义为整数,然后再进行数学运算时就不会被当做字符串了。功能有限,仅支持最基本的数学运算(加减乘除和取余),不支持逻辑运算、自增自减等,所以在实际开发中很少使用。

(()) : 整数运算

运算操作符/运算命令说明
((a=10+66) ((b=a-15)) ((c=a+b))这种写法可以在计算完成后给变量赋值。以 ((b=a-15)) 为例,即将 a-15 的运算结果赋值给变量 c。 注意,使用变量时不用加$前缀,(( )) 会自动解析变量名。
a= ( ( 10 + 66 ) b = ((10+66) b= ((10+66)b=((a-15)) c=$((a+b))可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c= ( ( a + b ) ) 为 例 , 即 将 a + b 这 个 表 达 式 的 运 算 结 果 赋 值 给 变 量 c 。 注 意 , 类 似 c = ( ( a + b ) ) 这 样 的 写 法 是 错 误 的 , 不 加 ‘ ((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。 注意,类似 c=((a+b)) 这样的写法是错误的,不加` ((a+b))a+bcc=((a+b))`就不能取得表达式的结果。
((a>7 && b==c))(( )) 也可以进行逻辑运算,在 if 语句中常会使用逻辑运算。
echo $((a+10))需要立接输出表达式的运算结果时,可以在 (( )) 前面加$符号。
((a=3+5, b=a+10))对多个表达式同时进行计算。

let : 整数运算

和双小括号 (( )) 一样,let 命令也只能进行整数运算,不能对小数(浮点数)或者字符串进行运算

let 表达式
#当表达式中含有 Shell 特殊字符(例如 |)时,需要用双引号" "或者单引号' '将表达式包围起来
  • 1
  • 2

和 (( )) 类似,let 命令也支持一次性计算多个表达式,并且以最后一个表达式的值作为整个 let 命令的执行结果。但是,对于多个表达式之间的分隔符,let 和 (( )) 是有区别的:

  • let 命令以空格来分隔多个表达式;
  • (( )) 以逗号,来分隔多个表达式。

另外还要注意,对于类似let x+y这样的写法,Shell 虽然计算了 x+y 的值,但却将结果丢弃;若不想这样,可以使用let sum=x+y将 x+y 的结果保存在变量 sum 中。

$[] : 整数计算

#$[] 会对表达式进行计算,并取得计算结果。如果表达式中包含了变量,那么你可以加$,也可以不加
#需要注意的是,不能单独使用 $[],必须能够接收 $[] 的计算结果
$[表达式]
#示例
$ echo $[$m*$n]
  • 1
  • 2
  • 3
  • 4
  • 5

expr

expr 是 evaluate expressions 的缩写,译为“表达式求值”。Shell expr 是一个功能强大,并且比较复杂的命令,它除了可以实现整数计算,还可以结合一些选项对字符串进行处理,例如计算字符串长度、字符串比较、字符串匹配、字符串提取等。

expr 对

表达式
  • 1

的格式有几点特殊的要求:

  • 出现在表达式中的运算符、数字、变量和小括号的左右两边至少要有一个空格,否则会报错。
  • 有些特殊符号必须用反斜杠\进行转义(屏蔽其特殊含义),比如乘号*和小括号(),如果不用\转义,那么 Shell 会把它们误解为正则表达式中的符号(*对应通配符,()对应分组)。
  • 使用变量时要加$前缀
[c.biancheng.net]$ m=5
[c.biancheng.net]$ n=`expr $m + 10`
[c.biancheng.net]$ echo $n
15

[c.biancheng.net]$ expr \( 2 + 3 \) \* 4  #使用 \ 转义
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

bc : 计算器

Link : http://c.biancheng.net/view/2680.html

  • bc 命令选项
选项说明
-h | --help帮助信息
-v | --version显示命令版本信息
-l | --mathlib使用标准数学库
-i | --interactive强制交互
-w | --warn显示 POSIX 的警告信息
-s | --standard使用 POSIX 标准来处理
-q | --quiet不显示欢迎信息
  • bc 有四个内置变量
变量名作 用
scale指定精度,也即小数点后的位数;默认为 0,也即不使用小数部分。
ibase指定输入的数字的进制,默认为十进制。
obase指定输出的数字的进制,默认为十进制。
last 或者 .表示最近打印的数字
  • 内置函数
s(x)计算 x 的正弦值,x 是弧度值。
c(x)计算 x 的余弦值,x 是弧度值。
a(x)计算 x 的反正切值,返回弧度值。
l(x)计算 x 的自然对数。
e(x)求 e 的 x 次方。
j(n, x)贝塞尔函数,计算从 n 到 x 的阶数
  • 在 Shell 中使用 bc 计算器
$ echo "expression" | bc
$ variable=$(echo "expression" | bc)

[c.biancheng.net]$ echo "scale=5;n=$x+2;e(n)"|bc -l
403.42879

variable=$(bc << EOF
expressions
EOF
)
#其中,variable是 Shell 变量名,express是要计算的数学表达式(可以换行,和进入 bc 以后的书写形式一样),EOF是数学表达式的开始和结束标识(你也可以换成其它的名字,比如 aaa、bbb 等)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

if else

#demo
if  condition1
then
   statement1
elif condition2
then
    statement2
elif condition3
then
    statement3
……
else
   statementn
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

内建命令test

用法

$ test expression
#也可以简写为[],注意[]和expression之间的空格,这两个空格是必须的,否则会导致语法错误
$ [ expression ]
  • 1
  • 2
  • 3

与文件检测相关的 test 选项

文件类型判断
选 项作 用
-b filename判断文件是否存在,并且是否为块设备文件。
-c filename判断文件是否存在,并且是否为字符设备文件。
-d filename判断文件是否存在,并且是否为目录文件。
-e filename判断文件是否存在。
-f filename判断文件是否存在,井且是否为普通文件。
-L filename判断文件是否存在,并且是否为符号链接文件。
-p filename判断文件是否存在,并且是否为管道文件。
-s filename判断文件是否存在,并且是否为非空。
-S filename判断该文件是否存在,并且是否为套接字文件。
文件权限判断
选 项作 用
-r filename判断文件是否存在,并且是否拥有读权限。
-w filename判断文件是否存在,并且是否拥有写权限。
-x filename判断文件是否存在,并且是否拥有执行权限。
-u filename判断文件是否存在,并且是否拥有 SUID 权限。
-g filename判断文件是否存在,并且是否拥有 SGID 权限。
-k filename判断该文件是否存在,并且是否拥有 SBIT 权限。
文件比较
选 项作 用
filename1 -nt filename2判断 filename1 的修改时间是否比 filename2 的新。
filename -ot filename2判断 filename1 的修改时间是否比 filename2 的旧。
filename1 -ef filename2判断 filename1 是否和 filename2 的 inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法

与数值比较相关的 test 选项

选 项作 用
num1 -eq num2判断 num1 是否和 num2 相等。
num1 -ne num2判断 num1 是否和 num2 不相等。
num1 -gt num2判断 num1 是否大于 num2 。
num1 -lt num2判断 num1 是否小于 num2。
num1 -ge num2判断 num1 是否大于等于 num2。
num1 -le num2判断 num1 是否小于等于 num2。

与字符串判断相关的 test 选项

选 项作 用
-z str判断字符串 str 是否为空。
-n str判断宇符串 str 是否为非空。
str1 = str2 str1 == str2===是等价的,都用来判断 str1 是否和 str2 相等。
str1 != str2判断 str1 是否和 str2 不相等。
str1 > str2判断 str1 是否大于 str2。\>>的转义字符,这样写是为了防止>被误认为成重定向运算符。
str1 < str2判断 str1 是否小于 str2。同样,\<也是转义字符。

C语言C++PythonJava 等编程经验的读者请注意,==、>、< 在大部分编程语言中都用来比较数字,而在 Shell 中,它们只能用来比较字符串,不能比较数字,这是非常奇葩的,大家要习惯。

其次,不管是比较数字还是字符串,Shell 都不支持 >= 和 <= 运算符,切记

与逻辑运算相关的 test 选项

选 项作 用
expression1 -a expression逻辑与,表达式 expression1 和 expression2 都成立,最终的结果才是成立的。
expression1 -o expression2逻辑或,表达式 expression1 和 expression2 有一个成立,最终的结果就成立。
!expression逻辑非,对 expression 进行取反。

test 用变量建议用双引号包起来

内置关键字[[]]

几乎完全兼容 test ,并且比 test 更加强大,比 test 更加灵活的是[[ ]][[ ]]不是命令,而是 Shell 关键字

#用法
$ [[ expression ]]
  • 1
  • 2

[[ ]] 是 Shell 内置关键字,不是命令,在使用时没有给函数传递参数的过程,所以 test 命令的某些注意事项在 [[ ]] 中就不存在了,具体包括:

  • 不需要把变量名用双引号""包围起来,即使变量是空值,也不会出错。
  • 不需要、也不能对 >、< 进行转义,转义后会出错。

[[ ]] 支持逻辑运算符

注意,[[ ]] 剔除了 test 命令的-o-a选项,你只能使用 || 和 &&

[[ ]] 支持正则表达式

$ [[ str =~ regex ]]
  • 1

但是 [[ ]] 对数字的比较仍然不友好,所以我建议,以后大家使用 if 判断条件时,用 (()) 来处理整型数字,用 [[ ]] 来处理字符串或者文件

关键字case in

case expression in
    pattern1)
        statement1
        ;;
    pattern2)
        statement2
        ;;
    pattern3)
        statement3
        ;;
    ……
    *)
        statementn
esac
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

case、int 和 esac 都是 Shell 关键字,expression 表示表达式,pattern 表示匹配模式。

  • expression 既可以是一个变量、一个数字、一个字符串,还可以是一个数学计算表达式,或者是命令的执行结果,只要能够得到 expression 的值就可以。
  • pattern 可以是一个数字、一个字符串,甚至是一个简单的正则表达式。

case 会将 expression 的值与 pattern1、pattern2、pattern3 逐个进行匹配:

  • 如果 expression 和某个模式(比如 pattern2)匹配成功,就会执行这模式(比如 pattern2)后面对应的所有语句(该语句可以有一条,也可以有多条),直到遇见双分号;;才停止;然后整个 case 语句就执行完了,程序会跳出整个 case 语句,执行 esac 后面的其它语句。
  • 如果 expression 没有匹配到任何一个模式,那么就执行*)后面的语句(*表示其它所有值),直到遇见双分号;;或者esac才结束。*)相当于多个 if 分支语句中最后的 else 部分

除最后一个分支外(这个分支可以是普通分支,也可以是*)分支),其它的每个分支都必须以;;结尾,;;代表一个分支的结束,不写的话会有语法错误。最后一个分支可以写;;,也可以不写,因为无论如何,执行到 esac 都会结束整个 case in 语句

case in 的 pattern 部分支持简单的正则表达式,具体来说,可以使用以下几种格式

格式说明
*表示任意字符串。
[abc]表示 a、b、c 三个字符中的任意一个。比如,[15ZH] 表示 1、5、Z、H 四个字符中的任意一个。
[m-n]表示从 m 到 n 的任意一个字符。比如,[0-9] 表示任意一个数字,[0-9a-zA-Z] 表示字母或数字。
|表示多重选择,类似逻辑运算中的或运算。比如,abc | xyz 表示匹配字符串 “abc” 或者 “xyz”。

while

while condition
do
    statements
done
  • 1
  • 2
  • 3
  • 4

until

until condition
do
    statements
done
#unti 循环和 while 循环恰好相反,当判断条件不成立时才进行循环,一旦判断条件成立,就终止循环
  • 1
  • 2
  • 3
  • 4
  • 5

for

#c风格
for((exp1; exp2; exp3))
do
    statements
done
#python风格
for variable in value_list
do
    statements
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

对 value_list 的说明

  • 直接给出具体的值

    #!/bin/bash
    for str in "C语言中文网" "http://c.biancheng.net/" "成立7年了" "日IP数万"
    do
        echo $str
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 给出一个取值范围
    #{start..end}
    #demo
    #!/bin/bash
    sum=0
    for n in {1..100}
    do
        ((sum+=n))
    done
    echo $sum
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    start 表示起始值,end 表示终止值;注意中间用两个点号相连,而不是三个点号。根据笔者的实测,这种形式只支持数字和字母

    再如,输出从 A 到 z 之间的所有字符

    #!/bin/bash
    for c in {A..z}
    do
        printf "%c" $c
    done
    #结果为:ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz
    #可以发现,Shell 是根据 ASCII 码表来输出的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 使用命令的执行结果
    #!/bin/bash
    sum=0
    for n in $(seq 2 2 100)
    do
        ((sum+=n))
    done
    echo $sum
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 使用 Shell 通配符
    #!/bin/bash
    for filename in *.sh
    do
        echo $filename
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 使用特殊变量
    #!/bin/bash
    function func(){
        for str in $@
        do
            echo $str
        done
    }
    func C++ Java Python C#
    
    #其实,我们也可以省略 value_list,省略后的效果和使用$@一样
    #!/bin/bash
    function func(){
        for str
        do
            echo $str
        done
    }
    func C++ Java Python C#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

select in

select variable in value_list
do
    statements
done
  • 1
  • 2
  • 3
  • 4

注意,select 是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到 break 语句,或者按下 Ctrl+D 组合键才能结束循环

select in 通常和 case in 一起使用,在用户输入不同的编号时可以做出不同的反应

#!/bin/bash
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
do
    case $name in
        "Linux")
            echo "Linux是一个类UNIX操作系统,它开源免费,运行在各种服务器设备和嵌入式设备。"
            break
            ;;
        "Windows")
            echo "Windows是微软开发的个人电脑操作系统,它是闭源收费的。"
            break
            ;;
        "Mac OS")
            echo "Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。"
            break
            ;;
        "UNIX")
            echo "UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。"
            break
            ;;
        "Android")
            echo "Android是由Google开发的手机操作系统,目前已经占据了70%的市场份额。"
            break
            ;;
        *)
            echo "输入错误,请重新输入"
    esac
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
#运行结果示例
What is your favourite OS?
1) Linux
2) Windows
3) Mac OS
4) UNIX
5) Android
#? 7
输入错误,请重新输入
#? 4
UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

break and continue

#可以跳出多层循环,不加n默认当前循环
break n
continue n
  • 1
  • 2
  • 3

输入输出重定向

Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符**(File Descriptor)**

文件描述符文件名类型硬件
0stdin标准输入键盘
1stdout标准输出显示器
2stderr标准错误输出显示器

Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。

stdin、stdout、stderr 默认都是打开的,在重定向的过程中,0、1、2 这三个文件描述符可以直接使用

输出重定向

输出重定向是指命令的结果不再输出到显示器上,而是输出到其它地方,一般是文件中。这样做的最大好处就是把命令的结果保存起来,当我们需要的时候可以随时查询。Bash 支持的重定向符号如下表所示

类 型符 号作 用
标准输出重定向命令 > 文件以覆盖的方式,把命令的正确输出结果输出到指定的文件或设备中。
标准输出重定向命令 >> 文件以追加的方式,把命令的正确输出结果输出到指定的文件或设备中。
标准错误输出重定向命令 2> 文件以覆盖的方式,把命令的错误信息输出到指定的文件或设备中。
标准错误输出重定向命令 2>> 文件以追加的方式,把命令的错误信息输出到指定的文件或设备中。
正确输出和错误信息同时保存命令 > 文件 2> &1以覆盖的方式,把正确输出和错误信息同时保存到同一个文件中。
同上命令 >> 文件 2> &1以追加的方式,把正确输出和错误信息同时保存到同一个文件中。
同上命令 &> 文件以覆盖的方式,把正确输出和错误信息同时保存到同一个文件中。
同上命令 &>> 文件以追加的方式,把正确输出和错误信息同时保存到同一个文件中。
同上命令 >> 文件1 2>> 文件2把正确的输出追加到文件1中,把错误信息追加到文件2中。
  • /dev/null 文件

    如果你既不想把命令的输出结果保存到文件,也不想把命令的输出结果显示到屏幕上,干扰命令的执行,那么可以把命令的所有结果重定向到 /dev/null 文件中。如下所示:

    ls -l &> /dev/null
    
    • 1

输入重定向

输入重定向就是改变输入的方向,不再使用键盘作为命令输入的来源,而是使用文件作为命令的输入

符号说明
命令 < 文件将指定的文件作为命令的输入。
命令 << 分界符从标准输入(键盘)中读取数据,直到遇见分界符才停止。
命令 < 文件1 > 文件2将文件1作为命令的输入,并将命令的处理结果输出到文件2。
  • 举例 wc

    Linux wc 命令可以用来对文本进行统计,包括单词个数、行数、字节数,它的用法如下:

    wc  [选项]  [文件名]
    #其中,-c选项统计字节数,-w选项统计单词数,-l选项统计行数
    
    • 1
    • 2
  • 统计用户在终端输入的文本的行数

    [c.biancheng.net]$ wc -l << END
    > 123
    > 789
    > abc
    > xyz
    > END
    4
    #wc 命令会一直等待用输入,直到遇见分界符 END 才结束读取
    #<<之后的分界符可以自由定义,只要再碰到相同的分界符,两个分界符之间的内容将作为命令的输入(不包括分界符本身)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

模块化(内置命令source)

source 命令的用法为

$ source filename
#也可以简写为
$ . filename
  • 1
  • 2
  • 3

source 是 Shell 内置命令的一种,它会读取 filename 文件中的代码,并依次执行所有语句。你也可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限

#!/bin/bash
source func.sh
echo $(sum 10 20 55 15)
#source 后边可以使用相对路径,也可以使用绝对路径,这里我们使用的是相对路径
  • 1
  • 2
  • 3
  • 4

避免重复引入

可以在模块中额外设置一个变量,使用 if 语句来检测这个变量是否存在,如果发现这个变量存在,就 return 出去

在 Shell 中,return 除了可以退出函数,还能退出由 source 命令引入的脚本文件。

return 只能退出由 source 命令引入的脚本文件,对其它引入脚本的方式无效

if [ -n "$__MODULE_SH__" ]; then
    return
fi
__MODULE_SH__='module.sh'
echo "http://c.biancheng.net/shell/"
  • 1
  • 2
  • 3
  • 4
  • 5
#!/bin/bash
source module.sh
source module.sh
echo "here executed"
  • 1
  • 2
  • 3
  • 4
运行 main.sh,输出结果为:
http://c.biancheng.net/shell/
here executed
  • 1
  • 2
  • 3

内建命令列表

Bash Shell 含有许多常用的命令,这些命令都已经内建在了 Shell 中。在使用这些命令时,执行速度就要快很多

相比外部命令,内建命令提供了更高的性能,但 Shell 中包含的内建命令越多,消耗的内存就会越大,而有些命令几乎永远也不会用到

命令说明
:扩展参数列表,执行重定向操作
.读取并执行指定文件中的命令(在当前 shell 环境中)
alias为指定命令定义一个别名
bg将作业以后台模式运行
bind将键盘序列绑定到一个 readline 函数或宏
break退出 for、while、select 或 until 循环
builtin执行指定的 shell 内建命令
caller返回活动子函数调用的上下文
cd将当前目录切换为指定的目录
command执行指定的命令,无需进行通常的 shell 查找
compgen为指定单词生成可能的补全匹配
complete显示指定的单词是如何补全的
compopt修改指定单词的补全选项
continue继续执行 for、while、select 或 until 循环的下一次迭代
declare声明一个变量或变量类型。
dirs显示当前存储目录的列表
disown从进程作业表中刪除指定的作业
echo将指定字符串输出到 STDOUT
enable启用或禁用指定的内建shell命令
eval将指定的参数拼接成一个命令,然后执行该命令
exec用指定命令替换 shell 进程
exit强制 shell 以指定的退出状态码退出
export设置子 shell 进程可用的变量
fc从历史记录中选择命令列表
fg将作业以前台模式运行
getopts分析指定的位置参数
hash查找并记住指定命令的全路径名
help显示帮助文件
history显示命令历史记录
jobs列出活动作业
kill向指定的进程 ID(PID) 发送一个系统信号
let计算一个数学表达式中的每个参数
local在函数中创建一个作用域受限的变量
logout退出登录 shell
mapfile从 STDIN 读取数据行,并将其加入索引数组
popd从目录栈中删除记录
printf使用格式化字符串显示文本
pushd向目录栈添加一个目录
pwd显示当前工作目录的路径名
read从 STDIN 读取一行数据并将其赋给一个变量
readarray从 STDIN 读取数据行并将其放入索引数组
readonly从 STDIN 读取一行数据并将其赋给一个不可修改的变量
return强制函数以某个值退出,这个值可以被调用脚本提取
set设置并显示环境变量的值和 shell 属性
shift将位置参数依次向下降一个位置
shopt打开/关闭控制 shell 可选行为的变量值
source读取并执行指定文件中的命令(在当前 shell 环境中)
suspend暂停 Shell 的执行,直到收到一个 SIGCONT 信号
test基于指定条件返回退出状态码 0 或 1
times显示累计的用户和系统时间
trap如果收到了指定的系统信号,执行指定的命令
type显示指定的单词如果作为命令将会如何被解释
typeset声明一个变量或变量类型。
ulimit为系统用户设置指定的资源的上限
umask为新建的文件和目录设置默认权限
unalias刪除指定的别名
unset刪除指定的环境变量或 shell 属性
wait等待指定的进程完成,并返回退出状态码

环境变量列表

Bash Shell 还使用了许多环境变量。虽然环境变量不是命令,但它们通常会影响 Shell 命令的执行

可用 set 内建命令显示这些环境变量。对于不同的 Linux 发行版,开机时设置的默认 shell 环境变量经常会不一样

变量说明
*含有所有命令行参数(以单个文本值的形式)
@含有所有命令行参数(以多个文本值的形式)
#命令行参数数目
?最近使用的前台进程的退出状态码
-当前命令行选项标记
$当前shell的进程 ID (PID)
!最近执行的后台进程的 PID
0命令行中使用的命令名称
_shell 的绝对路径名
BASH用来调用 shell 的完整文件名
BASHOPTS允许冒号分隔列表形式的 Shell 选项
BASHPID当前 bash shell 的进程 ID
BASH_ALIASED含有当前所用别名的数组
BASH_ARGC当前子函数中的参数数量
BASH_ARGV含有所有指定命令行参数的数组
BASH_CMDS含有命令的内部散列表的数组
BASH_COMMAND当前正在被执行的命令名
BASH_ENV如果设置了的话,每个 bash 脚本都会尝试在运行前执行由该变量定义的起始文件
BASH_EXECUTION_STRING在 -c 命令行选项中用到的命令
BASH_LINENO含有脚本中每个命令的行号的数组
BASH_REMATCH含有与指定的正则表达式匹配的文本元素的数组
BASH_SOURCE含有 shell 中已声明函数所在源文件名的数组
BASH_SUBSHELL当前 shell 生成的子 shell 数目
BASH_VERS INFO含有当前 bash shell 实例的主版本号和次版本号的数组
BASH_VERS ION当前 bash shell 实例的版本号
BASH_XTRACEFD当设置一个有效的文件描述符整数时,跟踪输出生成,并与诊断和错误信息分离开文件描述符必须设置 -x 启动
COLUMNS含有当前 bash shell 实例使用的终端的宽度
COMP_CWORD含有变量 COMP_WORDS 的索引直,COMP_WORDS 包含当前光标所在的位置
COMP_KEY调用补全功能的按键
COMP_LINE当前命令行
COMP_POINT当前光标位置相对干当前命令起始位置的索引
COMP_TYPE补全类型所对应的整数值
COMP_WORDBREAKS在进行单词补全时闬作单词分隔符的一组字符
COMP_WORDS含有当前命令行上所有单词的数组
COMPREPLY含有由 shell 函数生成的可能补全码的数组
COPROC含有若干匿名协程 I/O 的文件描述符的数组
DIRSTACK含有目录栈当前内容的数组
EMACS如果设置了该环境变量,则 shell 认为其使用的是 emacs shell 缓冲区,同时禁止行编辑功能
ENV当 shell 以 POSIX 模式调用时,每个 bash 脚本在运行之前都会执行由该环境变量所定义的起始文件
EUID当前用户的有效用户 ID(数字形式)
FCEDITfc 命令使用的默认编辑器
FIGNORE以冒号分隔的后缀名列表,在文件名补全时会被忽略
FUNCNAME当前执行的 shell 函数的名称
FUNCNEST嵌套函数的最髙层级
GLOBIGNORE以冒号分隔的模式列表,定义了文件名展开时要忽略的文件名集合
GROUPS含有当前用户属组的数组
histchars控制历史记录展开的字符(最多可有3个)
HISTCMD当前命令在历史记录中的编号
HISTCONTROL控制哪些命令留在历史记录列表中
HISTFILE保存 shell 历史记录列表的文件名(默认是 .bash_history)
HISTFILESIZE保存在历史文件中的最大行数
HISTIGNORE以冒号分隔的模式列表,用来决定哪些命令不存进历史文件
HISTSIZE最多在历史文件中保存多少条命令
HISTIMEFORMAT设置后,决定历史文件条目的时间戳的格式字符串
HOSTFILE含有 shell 在补全主机名时读取的文件的名称
HOSTNAME当前主机的名称
HOSTTYPE当前运行 bash shell 的机器
IGNOREEOFshell 在退出前必须收到连续的 EOF 字符的数量。如果这个值不存在,默认是 1
INPUTRCreadline 初始化文件名(默认是 .inputrc)
LANGshell 的语言环境分类
LC_ALL定义一个语言环境分类,它会覆盖 LANG 变量
LC_COLLATE设置对字符串值排序时用的对照表顺序
LC_CTYPE决定在进行文件名扩展和模式匹配时,如何解释其中的字符
LC_MESSAGES决定解释前置美元符($)的双引号字符串的语言环境设置
LC_NUMERIC决定格式化数字时的所使用的语言环境设置
LINENO脚本中当前执行代码的行号
LINES定义了终端上可见的行数
MACHTYPE用“cpu-公司-系统”格式定义的系统类型
MAILCHECKShell 多久查看一次新邮件(以秒为单位,默认值是 60)
MAPFILE含有 mapfile 命令所读入文本的数组,当没有给出变量名的时候,使用该环境变量
OLDPWDshell 之前的工作目录
OPTERR设置为 1 时,bash shell 会显示 getopts 命令产生的错误
OSTYPE定义了 shell 运行的操作系统
PIPESTATUS含有前台进程退出状态码的数组
POSIXLY_CORRECT如果设置了该环境变量,bash 会以 POSIX 模式启动
PPIDbash shell 父进程的 PID
PROMPT_COMMAND如果设置该环境变量,在显示命令行主提示符之前会执行这条命令
PS1主命令行提示符字符串
PS2次命令行提示符字符串
PS3select 命令的提示符
PS4如果使用了 bash 的 -x 选项,在命令行显示之前显示的提示符
PWD当前工作目录
RANDOM返回一个 0~32 767 的随机数,对其赋值可作为随机数生成器的种子
READLINE_LINE保存了 readline 行缓冲区中的内容
READLINE_POINT当前 readline 行缓冲区的插入点位置
REPLYread 命令的默认变量
SECONDS自 shell 启动到现在的秒数,对其赋值将会重置计时器
SHELLshell 的全路径名
SHELLOPTS已启用 bash shell 选项列表,由冒号分隔
SHLVL表明 shell 层级,每次启动一个新的 bash shell 时计数加 1
TIMEFORMAT指定了 shell 显示的时间值的格式
TMOUTselect 和 read 命令在没输入的情况下等待多久(以秒为单位)。默认值为零,表示无限长
TMPDIR如果设置成目录名,shell 会将其作为临时文件目录
UID当前用户的真实用户 ID (数字形式)
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号