当前位置:首页 > 运维 > 正文内容

linux中set指令用法

phpmianshi5年前 (2016-04-26)运维242

简介

我们知道,Bash 执行脚本的时候,会创建一个新的 Shell,这个 Shell 就是脚本的执行环境,Bash 默认给定了这个环境的各种参数。set命令用来修改 Shell 环境的运行参数,也就是可以定制环境。


语  法

[root@localhost ~]# help setset: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
    Set or unset values of shell options and positional parameters.
    设置或者复位shell选项的值和位置参数的值.    Change the value of shell attributes and positional parameters, or
    display the names and values of shell variables.
    改变shell属性的值和位置参数的值, 或者显示shell变量的名字和值.

    Options:
    (我删去了一些选项)
      -h  Remember the location of commands as they are looked up.
      -H  Enable ! style history substitution.  This flag is on
          by default when the shell is interactive.
      -v  Print shell input lines as they are read.
      -x  Print commands and their arguments as they are executed.      --  Assign any remaining arguments to the positional parameters.
          If there are no remaining arguments, the positional parameters
          are unset.
          将任何剩余的参数分配给位置参数, 如果没有剩余的参数, 就会将位置参数复位.
      -   Assign any remaining arguments to the positional parameters.
          The -x and -v options are turned off.
          将任何剩余的参数分配给位置参数. -x和-v选项会被关闭.    Using + rather than - causes these flags to be turned off.  The
    flags can also be used upon invocation of the shell.  The current
    set of flags may be found in $-.  The remaining n ARGs are positional    parameters and are assigned, in order, to $1, $2, .. $n.  If no
    ARGs are given, all shell variables are printed.
    使用 + 而不是 - 会导致这些标志被关闭. 这些标志还可以在调用shell时被使用.
    这些标志的当前的设置可以在 $- 中被找到. 剩余的n个参数是位置参数, 它们会被
    按顺序分配给 $1, $2, .. $n. 如果没有给出参数, 所有的shell变量会被打印出来.    Exit Status:    Returns success unless an invalid option is given.
    返回success, 除非给出了一个无效的参数.

补充说明

用set 命令可以设置各种shell选项或者列 出shell变量.单个选项设置常用的特性.在某些选项之后

-o参数将特殊特性打开.在某些选项之后使用

+o参数将关闭某些特性,不带任何参数的set命令将显示shell的全部变量.除非遇到非法的选项,否则set总是返回true

参数说明

allexport           -a         从设置开始标记所有新的和修改过的用于输出的变量        
braceexpand         -B         允许符号扩展,默认选项  
emacs                          在进行命令编辑的时候,使用内建的emacs编辑器, 默认选项
errexit            -e          如果一个命令返回一个非0退出状态值(失败),就退出.
histexpand         -H          在做临时替换的时候允许使用!和!! 默认选项
history                        允许命令行历史,默认选项
ignoreeof                      禁止coontrol-D的方式退出shell,必须输入exit。
interactive-comments           在交互式模式下, #用来表示注解
keyword             -k         为命令把关键字参数放在环境中
monitor             -m        允许作业控制
noclobber           -C        保护文件在使用重新动向的时候不被覆盖
noexec              -n        在脚本状态下读取命令但是不执行,主要为了检查语法结构。
noglob              -d        禁止路径名扩展,即关闭通配符    
notify              -b        在后台作业以后通知客户
nounset             -u        在扩展一个没有的设置的变量的时候,显示错误的信息    
onecmd              -t        在读取并执行一个新的命令后退出      
physical            -P         如果被设置,则在使用pwd和cd命令时不使用符号连接的路径 而是物理路径
posix                         改变shell行为以便符合POSIX要求
privileged                    一旦被设置,shell不再读取.profile文件和env文件 shell函数也不继承任何环境
verbose             -v        为调试打开verbose模式
vi                             在命令行编辑的时候使用内置的vi编辑器
xtrace             -x          打开调试回响模式

对于不知道某些选项是否开启,可以使用以下的指令:

set -o


查看各个参数的默认状态:

$ set -o
allexport       off
braceexpand     on
emacs           on
errexit         off
errtrace        off
functrace       off
hashall         on
histexpand      on
history         on

示例1.  set -e

若程序 异常(返回 非 true)值, 程序会继续向下执行。

errexit                 -e                        如果一个命令返回一个非0退出状态值(失败),就退出.

#! /bin/bash
set -e
#set -o errexit  另一种写法
foo
echo bar


示例2. set -x

默认情况下,脚本执行后,屏幕只显示运行结果,没有其他内容。如果多个命令连续执行,它们的运行结果就会连续输出。有时会分不清,某一段内容是什么命令产生的。

set -x用来在运行结果之前,先输出执行的那一行命令。

#! /bin/bash
set -x       # 执行指令前,先输出指令
#set -o xtrace  # 另一种写法
echo hello

示例3. set -u

对于一些变量 APP=   若忘记设置值,可能会导致 rm -rf /${APP}   变为 rm -rf /. 这是非常危险的操作。

nounset              -u                        在扩展一个没有的设置的变量的时候,    显示错误的信息    

执行脚本时,遇到不存在变量,bash报错并停止

! /bin/bash

set -u      # 注释与不注释执行结果不同
#set -o nounset  #另一种写法
echo $a
echo hello

示例4. set -o pipefail

set -e有一个例外情况,就是不适用于管道命令。

所谓管道命令,就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e就失效了。

请看下面这个例子

#!/bin/bash

set -e

foo | echo a

echo bar

执行结果如下。

$ bash script.sh

a

script.sh:行4: foo: 未找到命令

bar

上面代码中,foo是一个不存在的命令,但是foo | echo a这个管道命令会执行成功,导致后面的echo bar会继续执行。

set -o pipefail用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行。

set -eo pipefail

foo | echo a

echo bar

运行后,结果如下

$ bash script.sh

a

script.sh:行4: foo: 未找到命令

可以看到,echo bar没有执行。

总结

set命令的上面这四个参数,一般都放在一起使用。

# 写法一 set -euxo pipefail

# 写法二 set -eux

set -o pipefail

这两种写法建议放在所有 Bash 脚本的头部。

另一种办法是在执行 Bash 脚本的时候,从命令行传入这些参数。

$ bash -euxo pipefail script.sh


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章


1、应用程序中调用read() 方法,这里会涉及到一次上下文切换(用户态->内核态),底层采用DMA(direct memory access)读取磁盘的文件,并把内容存储到内核地址空间的读取缓存区。

操作系统检测到进程向I/O设备发起请求后就暂停进程的运行,怎么暂停运行呢?

很简单:只需要记录下当前进程的运行状态并把CPU的PC寄存器指向其它进程的指令就可以了。
进程有暂停就会有继续执行,因此操作系统必须保存被暂停的进程以备后续继续执行,显然我们可以用队列来保存被暂停执行的进程。

注意:现代磁盘向内存copy数据时无需借助CPU的帮助,这就是所谓的DMA(Direct Memory Access)。

实际上:操作系统中除了有阻塞队列之外也有就绪队列,所谓就绪队列是指队列里的进程准备就绪可以被CPU执行了。
你可能会问为什么不直接执行非要有个就绪队列呢?

答案很简单:那就是僧多粥少,在即使只有1个核的机器上也可以创建出成千上万个进程,CPU不可能同时执行这么多的进程,因此必然存在这样的进程,即使其一切准备就绪也不能被分配到计算资源,这样的进程就被放到了就绪队列。

当进程A被暂停执行后CPU是不可以闲下来的,因为就绪队列中还有嗷嗷待哺的进程B,这时操作系统开始在就绪队列中找下一个可以执行的进程,也就是这里的进程B。
此时操作系统将进程B从就绪队列中取出,找出进程B被暂停时执行到的机器指令的位置,然后将CPU的PC寄存器指向该位置,这样进程B就开始运行啦。

此后磁盘终于将全部数据都copy到了进程A的内存中,这时磁盘通知操作系统任务完成啦,你可能会问怎么通知呢?这就是中断
操作系统接收到磁盘中断后发现数据copy完毕,进程A重新获得继续运行的资格,这时操作系统小心翼翼的把进程A从阻塞队列放到了就绪队列当中。

注意:从前面关于就绪状态的讨论中我们知道,操作系统是不会直接运行进程A的,进程A必须被放到就绪队列中等待,这样对大家都公平。

此后进程B继续执行,进程A继续等待,进程B执行了一会儿后操作系统认为进程B执行的时间够长了,因此把进程B放到就绪队列,把进程A取出并继续执行。

注意:操作系统把进程B放到的是就绪队列,因此进程B被暂停运行仅仅是因为时间片到了而不是因为发起I/O请求被阻塞。

进程A继续执行,此时buff中已经装满了想要的数据,进程A就这样愉快的运行下去了,就好像从来没有被暂停过一样


2、由于应用程序无法读取内核地址空间的数据,如果应用程序要操作这些数据,必须把这些内容从读取缓冲区拷贝到用户缓冲区。这个时候,read() 调用返回,且引发一次上下文切换(内核态->用户态),现在数据已经被拷贝到了用户地址空间缓冲区,这时,如果有需要,应用程序可以操作修改这些内容。

3、我们最终目的是把这个文件内容通过Socket传到另一个服务中,调用Socket的send()方法,这里又涉及到一次上下文切换(用户态->内核态),同时,文件内容被进行第三次拷贝,被再次拷贝到内核地址空间缓冲区,但是这次的缓冲区与目标套接字相关联,与读取缓冲区没有半点关系。

4、send()调用返回,引发第四次的上下文切换,同时进行第四次的数据拷贝,通过DMA把数据从目标套接字相关的缓存区传到协议引擎进行发送。

"在整个过程中,过程1和4是由DMA负责,并不会消耗CPU,只有过程2和3的拷贝需要CPU参与


如果在应用程序中,不需要操作内容,过程2和3就是多余的,如果可以直接把内核态读取缓存冲区数据直接拷贝到套接字相关的缓存区,是不是可以达到优化的目的?

Linux中nio的实现原理

我们上一篇文章 《linux中netstat和ss命令详解》中提到了nio 原文:https://phpmianshi.com/?id=105有一些小伙伴私信想了解什么是nio,我们这篇详细介绍下什么...

linux中Cannot assign requested address的问题处理

问题描述:最近系统报警有类型如下错误:Cannot assign requested address  主要是连接mysql时产生的错误。分析原因:客户端与服务端每建立一个连接,客户端一侧都...

Nginx中对同一IP限速限流DDOS预防

作用:Nginx通过limit_conn_zone和limit_req_zone对同一个IP地址进行限速限流,可防止DDOS/CC和flood攻击limit_conn_zone是限制同一个IP的连接数...

Certbot-免费的https证书

什么是HTTPS?HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传...

linux中netstat和ss命令详解

由于nio的普及,ck10k的问题已经成为过去式。现在随便一台服务器,都可以支持数十万级别的连接了。那么10万的连接需要多少资源呢?由于一个连接都是文件句柄,所以需要文件描述符数量支持才行,每一个so...

linux中如何排查负载过高的问题

概况Linux的负载高,主要是由于CPU使用、内存使用、IO消耗三部分构成。任意一项使用过多,都将导致服务器负载的急剧攀升。如何判断系统是否已经Over Loadw、uptime、top 等命令都可以...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。