zoukankan      html  css  js  c++  java
  • shell内建命令

    <<<作用
    * cmd <<< word
    把word字符串(而不是文件word)和后面的换行作为输入提供给cmd。
    例如:
    [root@snow zc]# cat <<< "hello" > 123.txt
    [root@snow zc]# ls
    123.txt  perl5  word  zc.sh
    [root@snow zc]# cat 123.txt
    hello
    [root@snow zc]# : >123.txt          冒号后面有空格,: > 代表清空123.txt文件
    [root@snow zc]# cat 123.txt
    [root@snow zc]#
    冒号作用
    {str:=expr}
    如果变量str不为空,${str:=expr}就等于str的值,若str为空,就把expr的值赋值给str。
    例如:
    [root@localhost ~]# ${abc:=t1}
    -bash: t1: command not found
    [root@localhost ~]# : ${abc:=t1}   冒号后面有空格
    [root@localhost ~]# echo $abc
    t1
    [root@localhost ~]# echo $?
    0
    注释:
    在第一条赋值命令中,若abc为空,则将t1赋值给abc,同时将t1作为命令来执行,但是并没有t1这个命令故报错。
    在第二条赋值命令中,若abc为空,则将t1赋值给abc,同时将t1作为参数传递给:空命令执行,且返回值为0。
    
    作用一: 占位符
    #!/bin/bash
    var=0
    if [ "$var" = "0" ]; then
        :
    else
        :  
    fi
    
    作用二: 空命令,与内建的true相同
    #!/bin/bash
    while :
    do
        echo "dead loop..."
    done
    
    作用三: 与>结合结合使用,用于清空文件
    [root@localhost ~#] : > data.log              # 清空文件
    [root@localhost ~#] cat /dev/null > data.log  # 等同于于这种
     示例二 清空文件
    [root@node56 ~]# cat <<<"Hello" >123.txt 
    [root@node56 ~]# cat 123.txt 
    Hello
    [root@node56 ~]# : >123.txt 
    [root@node56 ~]# cat 123.txt 
    [root@node56 ~]#
    
    作用四: 注释
    单行注释
    : your comment here    冒号后面有空格
    等价于
    # your comment here
    
    多行注释
    :  'comment line1   冒号后面有空格
    comment line2
    more comments'
    
    例如:
    :  this is single line comment   冒号后面有空格
      
    :  'this is a multiline comment,  冒号后面有空格
    second line  
    end of comments'
    
    示例三 脚本注释、占位符
    脚本test_colon.sh
    #!/bin/sh   
    : this is single line comment     脚本注释
      
    : 'this is a multiline comment,    脚本注释
    second line  
    end of comments'  
      
    if [ "1" == "1" ]; then  
            echo "yes"  
    else  
            :          占位符
    fi  
    点号作用
    想在当前shell脚本中,调用另外一个shell库里面的函数,可以使用点号(.)或者source命令。
    例如:
    [root@snow zc]# cat lss.sh
    #!/bin/bash
    ls -al
    echo
    echo
    .  /home/zc/zc.sh       点号(.)后面有空格,且是绝对路径
    [root@snow zc]#
    
    source命令的作用就是用来执行一个脚本,那么: source a.sh 同直接执行 ./a.sh 有什么不同呢?
    比如您在一个脚本里export $KKK=111,假如您用./a.sh执行该脚本,执行完毕后,您运行echo $KKK,发现没有值,
    假如您用source来执行,然后再echo ,就会发现KKK=111。因为调用./a.sh来执行shell是在一个子shell里运行的,
    所以执行后,结果并没有反应到父shell里,但是source不同他就是在本shell中执行的,所以能够看到结果。 经典问题: shell脚本(test.
    sh)如下: #!/bin/sh echo "export monitor=1" >> /etc/profile source /etc/profile 调用后(./test.sh),执行echo $monitor,没有输出任何值 手动source /etc/profile后,再次执行echo $monitor,输出了预期的值 可见脚本中的source /etc/profile没有成功(提法本身就是错误的),请问这个应该怎么解决? A:在执行test.sh的时候,不用./test.sh 用source test.sh
    alias实现命令别名
    1.显示当前设置的所有别名:
    [root@snow zc]# alias
    alias cdp='cd /root/zhangchao'
    alias cdz='cd /home/zc'
    alias cp='cp -i'
    2.只显示某个别名代表的含义可输入alias name
    [root@snow zc]# alias ll
    alias ll='ls -l --color=auto'
    [root@snow zc]#
    3.为命令设置别名可输入alias 新命令='原命令 选项/参数'
    [root@snow zc]# alias cdz='cd /home/zc'
    4.取消命令别名
    [root@snow zc]# unalias ll
    5.一次执行多个命令
    a.首先使用命令 type 自定义命令名 ,查看自定义命令名是否被系统占用。
    [root@snow zc]# type ll
    ll is aliased to `ls -l --color=auto'
    [root@snow zc]# type loo
    -bash: type: loo: not found
    [root@snow zc]#
    b.使用命令alias创建自定义命令:alias loo='cd /root;ls;cd /' 。需要注意的是命令的使用格式,分号与分号之间是没有空格的。
    c.如果希望删除这个自定义命令,可以使用命令 unalias 自定义命令名 来完成
    6.别名永久生效
    那就是修改rc配置文件,把设置别名的过程加入到系统启动后初始化用户的脚本中, 用户只需要修改 ~/.bashrc文件, 加入你要设置的别名命令即可
    想要添加一个命令 oo  输入oo就能直接进入/mnt/hgfs/D/work/project/ASID/5.code/trunk/ASID/ASID/wms目录
    方法:vi /etc/bashrc
            在文件末尾添加alias oo='cd /mnt/hgfs/D/work/project/ASID/5.code/trunk/ASID/ASID/wms/'并保存退出
            执行source /etc/bashrc  使配置生效
            完成!
    bg、fg
    bg %num 即可将挂起的job的状态由stopped改为running,仍在后台执行; 当需要改为在前台执行时,执行命令fg %num即可;
    builtin命令
    用以执行shell的内建命令,既然是内建命令,为什么还要以这种方式执行呢?因为shell命令执行时首先从函数开始,如果自定义了一个与内建命令同名的函数,那么就执行这个函数而非真正的内建命令。
    $ umask
    0002
    $ umask() { echo "umask function"; }
    $ umask
    umask function
    $ builtin umask
    0002
    $ unset -f umask
    $ umask
    0002
    caller命令
    返回当前活动的子程序调用的上下文,即调用堆栈信息,包括shell函数和内建命令source执行的脚本。
    没有指定expr时,显示当前子程序调用的行号和源文件名。如果expr是一个非负整数,显示当前子程序调用的行号、子程序名和源文件名。
    caller命令打印出来的堆栈信息在调试程序时是很有帮助的,当前栈帧为0。如果shell没有子程序调用或者expr是一个无效的位置时,call命令返回false。 caller一般做调试用,打印出函数调用的行号和源文件名。 例如: foo() {
    echo "foo called" caller } bar() { echo "bar called" caller 0 } test1() { echo "test1 called" caller caller 0 caller 1 caller 2 } test2() { echo "test2 called" test1 } test3() { echo "test3 called" test2 } foo bar test3
    command命令
    类似于builtin,也是为了避免调用同名的shell函数,命令包括shell内建命令和环境变量PATH中的命令。选项“-p”指定在默认的环境变量PATH中查找命令路径。选项“-v”和“-V”用于显示命令的描述,后者显示的信息更详细。
    例如:
    [root@snow zc]# ps
      PID TTY          TIME CMD
     5826 pts/0    00:00:00 bash
     7019 pts/0    00:00:00 ps
    [root@snow zc]#
    [root@snow zc]# ps() { echo "function ps"; }
    [root@snow zc]# ps
    function ps
    [root@snow zc]# builtin ps            ps不是内建命令,是环境变量命令
    -bash: builtin: ps: not a shell builtin
    [root@snow zc]# command ps
      PID TTY          TIME CMD
     5826 pts/0    00:00:00 bash
     7020 pts/0    00:00:00 ps
    [root@snow zc]#
    disown 
    后台挂载,在后台运行用户进程,不受shell退出的影响,弥补没有使用&和nuhup。 disown 使已经在运行的用户进程 不受用户退出限制 disown -h %1 # 1 为jobsID 如果已经在当前终端运行 ;可以ctrl+z 挂起 ;bg jobsID 放入后台 disown -h jobsID #使已经在运行的用户进程 不受用户退出限制 用disown -h jobspec来使某个作业忽略HUP信号。 用disown -ah 来使所有的作业都忽略HUP信号。 用disown -rh 来使正在运行的作业忽略HUP信号。 需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。 disown命令可以从当前shell的作业列表中移除全部作业,也可移除指定的一到多个作业;正在运行的作业也可以移除;也可以标记作业,使得它们在当前shell退出后也不会结束。 该命令需要set选项monitor处于开启状态时才能执行;查看作业控制状态:输入set -o查看 monitor行;执行set -o monitor或set -m开启该选项。
    disown命令该命令是bash内建命令,相关的帮助信息请查看help命令。 语法格式 disown [参数] [标识符or进程ID] 常用参数:
    -h 标记每个作业标识符,这些作业将不会在shell接收到sighup信号时接收到sighup信号 -a 移除所有的作业 -r 移除运行的作业 参考实例 删除全部作业: [root@linux265 ~]# disown -a 删除运行状态的作业: [root@linux265 ~]# disown -r 根据jobId,移出指定的后台任务: [root@linux265 ~]# disown -h %2 一、键入不同 1、HUP中断信号:HUP中断信号是当用户键入<Ctrl+X>时由终端驱动程序发送的信号。 2、INT中断信号:INT中断信号是当用户键入<Ctrl+I>时由终端驱动程序发送的信号。 3、KILL中断信号:KILL中断信号是当用户键入<Ctrl+Z>时由终端驱动程序发送的信号。 4、TERM中断信号:TERM中断信号是当用户键入<Ctrl+ >时由终端驱动程序发送的信号。 5、TSTP中断信号:TSTP中断信号是当用户键入<Ctrl+T>时由终端驱动程序发送的信号。二、二、对应操作不同 1、HUP中断信号:HUP中断信号的对应操作为让进程挂起,睡眠。 2、INT中断信号:INT中断信号的对应操作为正常关闭所有进程。 3、KILL中断信号:KILL中断信号的对应操作为强制关闭所有进程。 4、TERM中断信号:TERM中断信号的对应操作为正常的退出进程。 5、TSTP中断信号:TSTP中断信号的对应操作为暂时停用进程。 三、启用不同 1、HUP中断信号:HUP中断信号发送后,可以重新被用户再次输入恢复启用进程。 2、INT中断信号:INT中断信号发送后,不可以重新被用户再次输入恢复启用进程。 3、KILL中断信号:KILL中断信号发送后,不可以重新被用户再次输入恢复启用进程。 4、TERM中断信号:TERM中断信号发送后,可以重新被用户再次输入启用进程。 5、TSTP中断信号:TSTP中断信号发送后,可以重新被用户再次输入继续使用进程。
    enable命令
    用于启动或关闭 shell 内建指令。
    若要执行的文件名称与shell内建指令相同,可用enable -n来关闭shell内建指令。若不加-n参数,enable可重新启动关闭的指令。
    eval
    eval主要用在对参数的特殊处理上面的,一般的命令行,shell处理参数就只执行一遍,像转义和变量转变;
    但加上eval后就可以对参数经行两遍处理;网上有说是对command
    -line处理两遍,我认为是不合理的。
    一个eval只能使shell对参数多一次处理,因此有几个eval就可以多加几次,即eval eval command-line
    这样就能对参数进行三次编译,但此时应特别注意参数的转义,下面有例子说明。 eval命令会计算(evalue)它的参数,这些参数作为表达式计算后重新组合为一个字符串,然后作为一个命令被执行。 eval最常见的用法是将动态生成的命令行计算并执行。例如: $ name
    =woodie $ cmd="echo Helllo $name! " $ eval $cmd Hello woodie! [root@localhost simon]#vim a.sh #!/bin/bash echo "$$#" 进程号+# echo "$$#" $+参数个数 eval echo "$$#" 最后一个参数值 [root@localhost simon]#./a.sh w s d 20621# $3 d
    exec 命令 
    命令代替shell程序,命令退出,shell 退出;比如 exec ls 这个命令还可以作为find命令的一个选项,如下所示: (1)在当前目录下(包含子目录),查找所有txt文件并找出含有字符串"bin"的行 find ./ -name "*.txt" -exec grep "bin" {} ; (2)在当前目录下(包含子目录),删除所有txt文件 find ./ -name "*.txt" -exec rm {} ; shell 中的 exec 两种用法: 1.exec 命令 ;命令代替shell程序,命令退出,shell 退出;比如 exec ls 2.exec 文件重定向,可以将文件的重定向就看为是shell程序的文件重定向 比如 exec 5</dev/null;exec 5<&- shell的内建命令exec将并不启动新的shell,而是用要被执行命令替换当前的shell进程,并且将老进程的环境清理掉,而且exec命令后的其它命令将不再执行。 因此,如果你在一个shell里面,执行exec ls那么,当列出了当前目录后,这个shell就自己退出了,因为这个shell进程已被替换为仅仅执行ls命令的一个进程,执行结束自然也就退出了。
    为了避免这个影响我们的使用,一般将exec命令放到一个shell脚本里面,用主脚本调用这个脚本,调用点处可以用bash a.
    sh,(a.sh就是存放该命令的脚本),
    这样会为a.sh建立一个sub shell去执行,当执行到exec后,该子脚本进程就被替换成了相应的exec的命令。 source命令或者
    ".",不会为脚本新建shell,而只是将脚本包含的命令在当前shell执行。 不过,要注意一个例外,当exec命令来对文件描述符操作的时候,就不会替换shell,而且操作完成后,还会继续执行接下来的命令。 exec 3<&0:这个命令就是将操作符3也指向标准输入。 另外,这个命令还可以作为find命令的一个选项,如下所示: (1)在当前目录下(包含子目录),查找所有txt文件并找出含有字符串"bin"的行 find ./ -name "*.txt" -exec grep "bin" {} ; (2)在当前目录下(包含子目录),删除所有txt文件 find ./ -name "*.txt" -exec rm {} ; 先总结一个表: exec命令 作用 exec ls 在shell中执行ls,ls结束后不返回原来的shell中了 exec <file 将file中的内容作为exec的标准输入 exec >file 将file中的内容作为标准写出 exec 3<file 将file读入到fd3中 sort <&3 fd3中读入的内容被分类 exec 4>file 将写入fd4中的内容写入file中 ls >&4 Ls将不会有显示,直接写入fd4中了,即上面的file中 exec 5<&4 创建fd4的拷贝fd5 exec 3<&- 关闭fd3 1. exec 执行程序 虽然exec和source都是在父进程中直接执行,但exec这个与source有很大的区别,source是执行shell脚本,而且执行后会返回以前的shell。
    而exec的执行不会返回以前的shell了,而是直接把以前登陆shell作为一个程序看待,在其上经行复制。 举例说明: root@localhost:
    ~/test#exec ls exp1 exp5 linux-2.6.27.54 ngis_post.sh test xen-3.0.1-install <logout> root@localhost:~/test#exec >text root@localhost:~/test#ls root@localhost:~/test#pwd root@localhost:~/test#echo "hello" root@localhost:~/test#exec>/dev/tty root@localhost:~/test#cat text exp1 exp5 linux-2.6.27.54 ngis_post.sh test text xen-3.0.1-install /root/test hello root@localhost:~/test# Exec >text 是将当前shell的标准输出都打开到text文件中 root@localhost:~/test#cat test ls Pwd root@localhost:~/test#bash root@localhost:~/test#exec <test root@localhost:~/test#ls exp1 exp5 linux-2.6.27.54 ngis_post.sh test text xen-3.0.1-install root@localhost:~/test#pwd /root/test root@localhost:~/test# root@localhost:~/test#exit #自动执行 2. exec的重定向 先上我们进如/dev/fd/目录下看一下: root@localhost:~/test#cd /dev/fd root@localhost:/dev/fd#ls 0 1 2 255 默认会有这四个项:0是标准输入,默认是键盘。 1是标准输出,默认是屏幕/dev/tty 2是标准错误,默认也是屏幕 255 当我们执行exec 3>test时: root@localhost:/dev/fd#exec 3>/root/test/test root@localhost:/dev/fd#ls 0 1 2 255 3 root@localhost:/dev/fd# 看到了吧,多了个3,也就是又增加了一个设备,这里也可以体会下linux设备即文件的理念。
    这时候fd3就相当于一个管道了,重定向到fd3中的文件会被写在test中。关闭这个重定向可以用exec
    3>&-。 root@localhost:/dev/fd#who >&3 root@localhost:/dev/fd#ls >&3 root@localhost:/dev/fd#exec 3>&- root@localhost:/dev/fd#cat /root/test/te test text root@localhost:/dev/fd#cat /root/test/test root tty1 2010-11-16 01:13 root pts/0 2010-11-15 22:01 (192.168.0.1) root pts/2 2010-11-16 01:02 (192.168.0.1) 0 1 2 255 3 3. 应用举例: exec 3<test while read -u 3 pkg do echo "$pkg" done . 系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。
    原进程的代码段,数据段,堆栈段被新的进程所代替。 一个进程主要包括以下几个方面的内容: (
    1)一个可以执行的程序 (2) 与进程相关联的全部数据(包括变量,内存,缓冲区) (3)程序上下文(程序计数器PC,保存程序执行的位置) 2. exec是一个函数簇,由6个函数组成,分别是以excl和execv打头的。 执行exec系统调用,一般都是这样,用fork()函数新建立一个进程,然后让进程去执行exec调用。
    我们知道,在fork()建立新进程之后,父进各与子进程共享代码段,但数据空间是分开的,但父进程会把自己数据空间的内容copy到子进程中去,还有上下文也会copy到子进程中去。
    而为了提高效率,采用一种写时copy的策略,即创建子进程的时候,并不copy父进程的地址空间,父子进程拥有共同的地址空间,
    只有当子进程需要写入数据时(如向缓冲区写入数据),这时候会复制地址空间,复制缓冲区到子进程中去。从而父子进程拥有独立的地址空间。
    而对于fork()之后执行exec后,这种策略能够很好的提高效率,如果一开始就copy,那么exec之后,子进程的数据会被放弃,被新的进程所代替。
    3. exec与system的区别 (1) exec是直接用新的进程去代替原来的程序运行,运行完毕之后不回到原先的程序中去。 (2) system是调用shell执行你的命令,system=fork+exec+waitpid,执行完毕之后,回到原先的程序中去。继续执行下面的部分。 总之,如果你用exec调用,首先应该fork一个新的进程,然后exec. 而system不需要你fork新进程,已经封装好了。 exec I/O重定向详解及应用实例 1、 基本概念(这是理解后面的知识的前提,请务必理解) a、 I/O重定向通常与 FD有关,shell的FD通常为10个,即 09; b、 常用FD有3个,为0(stdin,标准输入)、1(stdout,标准输出)、2(stderr,标准错误输出),默认与keyboard、monitor、monitor有关; c、 用 来改变送出的数据信道(stdout, stderr),使之输出到指定的档案; e、 0 是 与 1> 是一样的; f、 在IO重定向 中,stdout 与 stderr 的管道会先准备好,才会从 stdin 读进资料; g、 管道“|”(pipe line):上一个命令的 stdout 接到下一个命令的 stdin; h、 tee 命令是在不影响原本 I/O 的情况下,将 stdout 复制一份到档案去; i、 bash(ksh)执行命令的过程:分析命令-变量求值-命令替代(``和$( ))-重定向-通配符展开-确定路径-执行命令; j、 ( ) 将 command group 置于 sub-shell 去执行,也称 nested sub-shell,它有一点非常重要的特性是:
      继承父shell的Standard input, output, and error plus any other open file descriptors。 k、 exec 命令:常用来替代当前 shell 并重新启动一个 shell,换句话说,并没有启动子 shell。
      使用这一命令时任何现有环境都将会被清除。exec 在对文件描述符进行操作的时候,也只有在这时,exec 不会覆盖你当前的 shell 环境。
    2、cmd &n 使用系统调用 dup (2) 复制文件描述符 n 并把结果用作标准输出 &- 关闭标准输出 n&- 表示将 n 号输出关闭 上述所有形式都可以前导一个数字,此时建立的文件描述符由这个数字指定而不是缺省的 01。如: ... 2>file 运行一个命令并把错误输出(文件描述符 2)定向到 file。 ... 2>&1 运行一个命令并把它的标准输出和输出合并。(严格的说是通过复制文件描述符 1 来建立文件描述符 2 ,但效果通常是合并了两个流。) 我们对 2>&1详细说明一下 :2>&1 也就是 FD2=FD1 ,这里并不是说FD2 的值 等于FD1的值,因为 > 是改变送出的数据信道,
    也就是说把 FD2 的 “数据输出通道” 改为 FD1 的 “数据输出通道”。如果仅仅这样,这个改变好像没有什么作用,因为 FD2 的默认输出和 FD1的默认输出本来都是 monitor,一样的! 但是,当 FD1 是其他文件,甚至是其他 FD 时,这个就具有特殊的用途了。请大家务必理解这一点。
    3、 如果 stdin, stdout, stderr 进行了重定向或关闭, 但没有保存原来的 FD, 可以将其恢复到 default 状态吗? *** 如果关闭了stdin,因为会导致退出,那肯定不能恢复。 *** 如果重定向或关闭 stdout和stderr其中之一,可以恢复,因为他们默认均是送往monitor(但不知会否有其他影响)。
    如恢复重定向或关闭的 stdout: exec 1>&2 ,恢复重定向或关闭的stderr:exec 2>&1*** 如果stdout和stderr全部都关闭了,又没有保存原来的FD,可以用:exec 1>/dev/tty 恢复。 4、 cmd >a 2>a 和 cmd >a 2>&1 为什么不同? cmd >a 2>a :stdout和stderr都直接送往文件 a ,a文件会被打开两遍,由此导致stdout和stderr互相覆盖。 cmd >a 2>&1 :stdout直接送往文件a ,stderr是继承了FD1的管道之后,再被送往文件a 。a文件只被打开一遍,就是FD1将其打开。 我想:他们的不同点在于: cmd >a 2>a 相当于使用了两个互相竞争使用文件a的管道; 而cmd >a 2>&1 只使用了一个管道,但在其源头已经包括了stdout和stderr。 从IO效率上来讲,cmd >a 2>&1的效率应该更高! exec 0exec 1>outfilename # 打开文件outfilename作为stdout exec 2>errfilename # 打开文件 errfilename作为 stderr exec 0&- # 关闭 FD1 exec 5>&- # 关闭 FD5
    export
    Linux export 命令用于设置或显示环境变量。
    在 shell 中执行程序时,shell 会提供一组环境变量。export 可新增,修改或删除环境变量,供后续执行的程序使用。export 的效力仅限于该次登陆操作。
    语法
    export [-fnp][变量名称]=[变量设置值]
    参数说明:
    -f  代表[变量名称]中为函数名称。
    -n  删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。
    -p  列出所有的shell赋予程序的环境变量。
    
    # export MYENV=7 //定义环境变量并赋值
    # export -p
    declare -x HOME=“/root“
    declare -x LANG=“zh_CN.UTF-8“
    declare -x LANGUAGE=“zh_CN:zh“
    fc
    使用该指令显示历史命令,输入如下命令:
    [root@localhost ~]# fc -l -10     #显示10条历史命令
    1039     type -a grep
    1040     export
    1041     history 10
    hash命令
    显示、添加或清除哈希表>
    linux系统下的hash指令:
    说明:linux系统下会有一个hash表,当你刚开机时这个hash表为空,每当你执行过一条命令时,hash表会记录下这条命令的路径,就相当于缓存一样。
    第一次执行命令shell解释器默认的会从PATH路径下寻找该命令的路径,当你第二次使用该命令时,shell解释器首先会查看hash表,没有该命令才会去PATH路径下寻找。 hash表的作用:大大提高命令的调用速率。 hash的参数: [root@redhat
    ~]# hash  //输入hash或hash -l 可以查看hash表的内容,我刚开机所以为空 hash: hash table empty [root@redhat ~]# hash -l hash: hash table empty 当我执行过2条命令后再看: [root@redhat ~]# hash  //hash表会记录下执行该命令的次数,以及命令的绝对路径 hits command 1 /bin/cat 1 /bin/ls [root@redhat ~]# hash -l  //加参数-l既可以看到hash表命令的路径,也可以看到它的名字,说不定会有别名哦 builtin hash -p /bin/cat cat builtin hash -p /bin/ls ls [root@redhat ~]# hash -p /bin/ls bb  //添加hash表,可以看到我把ls命令重新写了一遍,改名为bb [root@redhat ~]# bb    //当我执行bb时就是执行ls命令 anaconda-ks.cfg icmp_echo_ignore_aly~ pub.key dead.letter icmp_echo_ignore_alz~ rpmbuild icmp_echo_ignore_all~ install.log RPM-GPG-KEY-useradd icmp_echo_ignore_alw~ install.log.syslog RPM-GPG-KEY-westos icmp_echo_ignore_alx~ passwd [root@redhat ~]# hash -t ls  //-t参数可以查看hash表中命令的路径,要是hash表中没有怎么办? /bin/ls [root@redhat ~]# hash -t df  //我没使用过df,执行hash,就会提示找不到该命令 -bash: hash: df: not found [root@redhat ~]# hash -r  //清楚hash表,清楚的是全部的 [root@redhat ~]# hash -l hash: hash table empty [root@redhat ~]# hash -l builtin hash -p /bin/cat cat builtin hash -p /bin/ls ls [root@redhat ~]# hash -d cat   //清楚其中的某一条 [root@redhat ~]# hash -l builtin hash -p /bin/ls ls
    let
    在shell中可以使用let来指示下面是算术表达式,let表达式内变量不用加$
    var=1
    let "var+=1" 或 let var+=1 这种写法运算符间不能有空格 
    echo $var
    output:
    2
    
    这其中的let可以用(())代替,let ″j=i*6+2″等价于((j=i*6+2)), 就像很多的循环中用法一样
    注意:let必须是完整的算术表达式,即有等号两边。(())、expr 可以只有等号右边的计算,由$((...))、$(expr ...)、`expr ...` 查看返回结果
    var=1
    ((var++))  查看结果: echo $(())
    echo $var
    output:
    2
    mapfile
    bash提供了两个内置命令:readarray和mapfile,它们是同义词。它们的作用是从标准输入读取一行行的数据,然后每一行都赋值给一个数组的各元素。
    显然,在shell编程中更常用的是从文件、从管道读取,不过也可以从文件描述符中读取数据。 需要先说明的是,shell并不像其它专门的编程语言对数组、列表提供了大量的操作工具,反而直接操作文本文件更为常见(
    sed、awk等),所以mapfile用的并不多。 1.语法 mapfile [OPTIONS] ARRAY readarray [OPTIONS] ARRAY 其中options: -O INDEX :指定从哪个索引号开始存储数据,默认存储数据的起始索引号为0 -n count :最多只拷贝多少行到数组中,如果count=0,则拷贝所有行 -s count :忽略前count行不读取 -c NUM :每读取NUM行就调用一次"-C callback"选项指定的callback程序 -C callback:每读取"-c NUM"选项指定的NUM行就执行一次callback回调程序 -d string :指定读取数据时的行分隔符,默认是换行符 -t :移除尾随行分隔符,默认是换行符 -u fd :指定从文件描述符fd而非标准输入中读取数据 •如果不指定ARRAY参数,则默认使用数组MAPFILE •如果不指定"-O"选项,则在存储数据之前先清空数组(如果该数组已存在) •给定了"-C callback"却没有给定"-c NUM"时,则默认为每5000行调用一次回调程序 •回调程序是在读取给定行数之后,赋值到数组元素之前执行的。所以流程为:"读NUM行-->callback-->赋值" •每次调用回调函数时,都将调用callback之前的最后一行数据及其对应的索引号作为回调程序的参数。
    例如
    -c 3 -C callback,则会将索引号2和第3行内容,索引号5和第6行内容作为callback程序的参数 •"-t"去除行尾分隔符,一般来说都是换行符。用其他语言编程过的人都知道行尾换行符有多烦心,但对于shell编程来说,倒是无所谓 2.几个示例和注意事项 先创建一个示例用的文件alpha.log,每行一个小写字母,共26行: $ echo {a..z} | tr " " " " >alpha.log $ cat alpha.log a b c d e f g h i j k l m n o p q r s t u v w x y z 读取该文件并将每一行存储到数组myarr中(如果不指定,则存储到默认的MAPFILE数组中)。 $ mapfile myarr <alpha.log $ echo ${myarr[@]} a b c d e f g h i j k l m n o p q r s t u v w x y z $ echo ${myarr[2]} c 既然是读取标准输入,常见的就有以下几种读取形式: $ mapfile myarr <alpha.log # 1.输入重定向 $ mapfile myarr < <(cat alpha.log) # 2.进程替换 $ cat alpha.log | mapfile myarr # 3.管道传递 第1、2种写法没什么问题,但第3种写法是有问题的。 $ cat alpha.log | mapfile myarr1 $ echo ${#myarr1[@]} 0 从结果中可以看到,myarr1根本就不存在。为什么?我在shell中while循环的陷阱中给出过解释。这里简单说明一下,对于管道组合的多个命令,
    它们都会放进同一个进程组中,会进入子shell执行相关操作。当执行完毕后,进程组结束,子shell退出。
    而子shell中设置的环境是不会粘滞到父shell中的(即不会影响父shell),所以myarr1数组是子shell中的数组,回到父shell就消失了。 解决方法是在子shell中操作数组: $
    cat alpha.log | { mapfile myarr1;echo ${myarr1[@]}; }
    readarray命令
    用于从标准输入或选项“-u”指定的文件描述符fd中读取文本行,然后赋值给索引(下标)数组array,如果不指定数组array,则使用默认的数组名MAPFILE。
    下面解释readarray命令中各选项的作用。
    “-n count”:复制最多count行,如果count为0,则复制所有的行。 
    “-O origin”:从下标位置origin开始对数组赋值,默认为0。 
    “-s count”:忽略开始读取的count行。 
    “-t”:删除文本行结尾的换行符。 
    “-u fd”:从文件描述符fd中读取文本行。 
    “-C callback”:每当读取选项“-c”指定的quantum行时(默认为5000行),就执行一次回调callback。
    下面以简单的例子说明readarray命令的用法:
    $ readarray foo
    hello world
    hello bash
    ^C
    $ echo ${foo[@]}
    hello world hello bash
    $ echo ${#foo[@]}
    2
    hanjunjie@hanjunjie-HP:~$ echo ${foo[0]}
    hello world
    hanjunjie@hanjunjie-HP:~$ echo ${foo[1]}
    hello bash
    set 用来显示本地变量
    env 用来显示环境变量
    export 用来显示和设置环境变量
    
    set 显示当前shell的变量,包括当前用户的变量
    env 显示当前用户的变量
    export 显示当前导出成用户变量的shell变量
    
    每个shell有自己特有的变量(set)显示的变量,这个和用户变量是不同的,当前用户变量和你用什么shell无关,
    不管你用什么shell都在,比如HOME,SHELL等这些变量,但shell自己的变量不同shell是不同的,比如BASH_ARGC, BASH等,
    这些变量只有set才会显示,是bash特有的,export不加参数的时候,显示哪些变量被导出成了用户变量,因为一个shell自己的变量可以通过export “导出”变成一个用户变量 [root@linux
    ~]# aaa=bbb [root@linux ~]# echo $aaa bbb [root@linux ~]# set|grep aaa aaa=bbb [root@linux ~]# env|grep aaa [root@linux ~]# export aaa [root@linux ~]# env|grep aaa aaa=bbb

    Bash 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 等待指定的进程完成,并返回退出状态码
  • 相关阅读:
    POJ1275 Cashier Employment 【二分 + 差分约束】
    POJ1201 Intervals 【差分约束】
    BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】
    BZOJ4197 [Noi2015]寿司晚宴 【状压dp】
    thusc2018酱油记
    HDU 4734
    Codeforces 55D
    HDU 3652
    HDU 4352
    HDU 3709
  • 原文地址:https://www.cnblogs.com/ggzhangxiaochao/p/13156387.html
Copyright © 2011-2022 走看看