上一篇我们讲了变量扩展、数学扩展和命令替换。本文随后介绍了shell中使用的其他扩展。历史扩展默认情况下,bash允许在交互式shell环境中记录和扩展历史命令。环境变量HISTSIZE的值定义了记录历史命令的条数,HISTFILE的值指定了交互式shell启动时需要加载的历史命令的配置文件。当交互式shell退出(exit)时,当前环境下执行的命令都会保存在这个配置文件中。当不带任何选项执行内置命令历史时,将输出所有记录的历史命令(共$HISTSIZE条)。[root@centos7~]#history4typetrue5helptrue6manbash7vimtest.sh8bash-xtest.sh...1003history环境变量HISTTIMEFORMAT的作用是控制输出的时间格式和记录历史命令(date命令的时间格式相同)。如:[root@centos7~]#exportHISTTIMEFORMAT="[%F%T]"[root@centos7~]#history|tail-21012[2017-01-1620:16:41]exportHISTTIMEFORMAT="[%F%T]"1013[2017-01-1620:16:52]history|tail-2由于bash脚本默认不能使用history命令,这里只简单介绍一些常用的用法。历史扩展操作符:!Event!n#Nthcommand!-n#Nthcommandbeforethecurrentcommand!!#Lastcommand,相当于!-1!string#最近执行的一个以string开头的命令!?string[?]#最近执行的一个包含string的命令,当字符串后面跟一个换行符时,尾部?可以省略。^string1^string2^#将前面命令中的string1替换成string2,执行。尾随的^可以省略。!##代表这个命令字符!#在事件之前键入的所有字符后面可以跟以冒号分隔的字符,表示选择特定参数(当冒号后面是^、$、*、-或%,冒号可以省略)如:!^#上一条命令的第一个参数!435:0#第435条命令的命令名!$#上一条命令的最后一个参数!*#上一条命令的所有参数都可以在冒号后面,表示对指定命令的修改:s/old/new/#替换第一个old,!!:s/string1/string2/和^string1^string2^表示同义g#用于全局替换,如!!:gs/string1/string2/AliasExpansion另一个默认只在交互式shell中可用的扩展是别名扩展。当一个词用作简单命令的第一个词时,bash允许使用字符串来替换该词(别名)。内置命令alias和unalias用于定义别名和取消别名。alias命令单独执行时,会列出系统中所有的别名。alias命令接受变量赋值格式的参数来设置别名。但是,别名的名称不像变量名的要求那么严格,别名可以包含除/、$、反引号、=、元字符和引号字符之外的任何字符。而别名的替换字符串可以是任何shell输入。[root@centos7~]#aliasaliascp='cp-i'aliasegrep='egrep--color=auto'aliasfgrep='fgrep--color=auto'aliasgrep='grep--color=auto'aliasl.='ls-d.*--color=auto'aliasll='ls-l--color=auto'aliasls='ls--color=auto'aliasmv='mv-i'aliasrm='rm-i'aliaswhich='别名|/usr/bin/which--tty-only--read-alias--show-dot--show-tilde'可以看到当我们执行ls命令时,输出结果文件的类型是用颜色区分的,因为ls是ls--color=auto的别名。默认情况下,shell脚本中不能使用别名。别名扩展完全基于文本,因此别名可以改变shell语法。几乎任何别名的功能都可以用shell函数来实现。大括号展开大括号展开是一种生成任意字符串的机制。正确的大括号扩展格式必须包含不带引号的大括号{},以及至少一个不带引号的逗号或序列表达式。任何不正确的格式将保持原样。在大括号内,如果需要{或者,可以在字符前添加反斜杠\以保持它们的文字。序列表达式的格式是:{x..y[..incr]}。其中x和y都是数字或单个英文字母,incr表示增量(必须是整数),..incr可以省略,省略表示增量为1或-1。批量创建文件[root@centos7tmp]#touch{a..l}.txt[root@centos7tmp]#lsa.txtb.txtc.txtd.txte.txtf.txtg.txth.txti.txtj.txtk.txtl.txt[root@centos7tmp]#花括号扩展类似于文件名的通配符匹配,但大括号扩展不需要文件存在。[root@centos7tmp]#ls[a-n].txta.txtb.txtc.txtd.txte.txtf.txtg.txth.txti.txtj.txtk.txtl.txt[root@centos7tmp]#ls{a..n}.txtls:无法访问m.txt:没有那个文件或目录ls:无法访问n.txt:没有那个文件或目录a.txtb.txtc.txtd.txte.txtf.txtg.txth.txti.txtj.txtk.txtl.txt大括号也可以嵌套如创建目录[root@centos7tmp]#mkdir-p./a{m,n/{1..3},o}x[root@centos7tmp]#找到.-typed../amx./an./an/1x./an/2x./an/3x./aox[root@centos7tmp]#当序列表达式中的数字以0开头时,展开后为0将添加在所有数字的前面,使它们宽度相等[root@centos7tmp]#echo{05..100..5}005010015020025030035040045050055060065070075080085090095100也可以用在for循环命令中[root@centos7tmp]#foriin{1..10..2};doecho$i;done13579[root@centos7tmp]#一个小技巧:#Backup[root@centos7tmp]#找到.-name'*.txt'-execcp{}{,.bak}\;[root@centos7tmp]#ls[a-z].txt{,.bak}a.txtb.txtc.txtd.txte.txtf.txtg.txth.txti.txtj.txtk.txtl.txta.txt.bakb.txt.bakc.txt.bakd.txt.bake.txt.bakf.txt.bakg.txt.bakh.txt.baki.txt.bakj.txt.bakk.txt.bakl.txt.bak#Mobile[root@centos7tmp]#mv{[a-z].txt.bak,amx}[root@centos7tmp]#lsamxanaoxa.txtb.txtc.txtd.txte.txtf.txtg.txth.txti.txtj.txtk.txtl.txt[root@centos7tmp]#lsamx/a.txt.bakb.txt.bakc.txt.bakd.txt.bake.txt.bakf.txt.bakg.txt.bakh.txt。baki.txt.bakj.txt.bakk.txt.bakl.txt.baktildeexpansionshell中以字符~开头的单词(不能被引号)也将被用作扩展方法(或用于变量赋值等号右边),下面给出一些例子:#word展开结果~$HOME~+$PWD~-$OLDPWD~user_name#用户user_name的主目录如[root@centos7tmp]#echo${PWD/#$HOME/~}/root/temp/tmp[root@centos7tmp]#echo"${PWD/#$HOME/~}"~/temp/tmp[root@centos7tmp]#进程替换我们说说语法到命令替换(格式:$(...)或`...`),它是命令执行和变量操作的结合。shell运行命令,收集其输出,并将输出用作扩展值。命令替换的一个问题是命令立即执行,然后等待结果,而shell无法传递输入。Bash使用称为进程替换的功能来弥补这些缺点。进程替换实际上是命令替换和管道的组合。与命令替换类似,bash运行一个命令,但让它在后台运行而不等待它完成。关键是Bash为这个命令打开了一个读写管道,绑定了一个文件名,最后展开为结果。进程替换的格式为:<(command)and>(command)。其展开的结果是一个文件(文件描述符):[root@centos7tmp]#echo<(ls)/dev/fd/63[root@centos7tmp]#所以可以使用命令查看文件得到进程输出:[root@centos7tmp]#cat<(ls)amxanaoxa.txtb.txtc.txtd.txte.txt...可以执行下面两条命令,尝试比较命令替换和进程的区别substitution:#sleep命令在echo结束后输出$(ls;sleep3)#sleep执行前输出结束cat<(ls;sleep3)脚本示例:#!/bin/bash#进程替换即可用作文件#作为输入文件,同时读取linedoARR+=("$line")done<<(seq100)#作为输出文件echo$((`echo-n${ARR[*]}>>(tr'''+')`))执行结果:[root@centos7temp]#./test.sh5050[root@centos7temp]#任务控制在允许任务控制的系统上,bash可以选择性地挂起一个前台进程并让它在后台异步继续。CTRL+Z可以暂停一个正在运行的前台进程:[root@centos7~]#sleep300^Z[1]+stoppedsleep300[root@centos7~]#[1]中的数字1表示第一个后台进程建立-在命令jobs中可以查看当前后台进程:[root@centos7~]#jobs[1]+stoppedsleep300[root@centos7~]#内置命令bg可以让挂起的进程继续在后台运行:[root@centos7~]#bg%1[1]+sleep300&[root@centos7~]#%1表示继续运行第一个后台进程,程序运行后会显示:[1]+completesleep300built-in命令fg可以将后台进程返回到前台继续运行:[root@centos7~]#fg%1sleep300^C[root@centos7~]#在交互式shell或脚本中,以控制运算符&也会作为后台命令异步执行,当前shell不会等待命令完成,命令返回码为0。在脚本中使用后台执行命令时需要注意。如果当前shell先于后台进程退出,则后台进程也会退出(此时执行未完成)。如果需要在父进程退出前等待后台进程退出,可以使用内置命令wait。脚本示例:#!/bin/bash#定义C段地址数组c=(12345)#测试连通性函数functionping_ip(){ping-c310.0.$i.$j&>/dev/null\||echo"10.0.$i.$jisnotused">>result.txt}#后台并发测试foriin${c[@]}doforjin{1..254}doping_ip&doneone#Waitfor所有后台进程略微结束等待执行
