在以前的文章中咱們講述了變量擴展
、數學擴展
和命令替換
。本篇接着介紹shell中用到的其餘擴展。shell
默認時,在交互式shell環境下,bash容許對歷史命令進行記錄和擴展。
環境變量HISTSIZE
的值定義了記錄歷史命令的條數,HISTFILE
的值指明瞭交互式shell啓動時須要加載的歷史命令的配置文件。在交互式shell退出時(exit),當前環境下執行過的命令會保存在此配置文件中。
當不帶任何選項執行內置命令history
時,將輸出全部記錄的歷史命令(共$HISTSIZE條)。vim
[root@centos7 ~]# history 4 type true 5 help true 6 man bash 7 vim test.sh 8 bash -x test.sh ... 1003 history
環境變量HISTTIMEFORMAT
的做用是控制輸出和記錄歷史命令的時間格式(和date命令的時間格式一致)。
如:centos
[root@centos7 ~]# export HISTTIMEFORMAT="[%F %T] " [root@centos7 ~]# history |tail -2 1012 [2017-01-16 20:16:41] export HISTTIMEFORMAT="[%F %T] " 1013 [2017-01-16 20:16:52] history |tail -2
因爲在bash腳本中,默認是不能使用歷史命令的,咱們這裏只簡要介紹一些經常使用的用法。
歷史擴展操做符:!
數組
事件 !n #第n條命令 !-n #當前命令以前第n條命令 !! #上一條命令,和!-1等價 !string #最近執行過的一條以string開頭的命令 !?string[?] #最近執行過的一條包含string的命令,當string後面就是換行符時,結尾的?能夠省略。 ^string1^string2^ #用string2替換上一條命令中的string1,並執行它。結尾的^能夠省略。 !# #表示本條命令字符!#以前鍵入的全部字符 事件以後能夠跟冒號分隔的以下字符,表示選擇特定的參數(當冒號後是 ^, $, *, -, 或 %時,冒號能夠省略) 如: !^ #前一條命令的第一個參數 !435:0 #第435條命令的命令名 !$ #前一條命令的最後一個參數 !* #前一條命令的全部參數 冒號後還能夠是以下字符,表示對指定命令的修改: s/old/new/ #替換第一個old,!!:s/string1/string2/ 和 ^string1^string2^ 表示一樣的意思 g #用於全局替換,如 !!:gs/string1/string2/
另外一個默認時只能在交互式shell中使用的擴展是別名擴展
。
當單詞做爲簡單命令的第一個單詞時,bash容許用字符串來替換這個單詞(別名)。
內置命令alias
和unalias
用來定義和撤銷別名。
單獨執行命令alias
時會列出系統中全部的別名,alias
命令接受形如變量賦值格式的參數來設定別名。但別名的名稱並不像變量名的要求那樣嚴格,別名能夠包含除了 /
,$
,反引號
,=
,元字符
和引用字符
以外的任意字符。而別名的替代字符串能夠是任何shell輸入。bash
[root@centos7 ~]# alias alias cp='cp -i' alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias rm='rm -i' alias which='alias | /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@centos7 tmp]# touch {a..l}.txt [root@centos7 tmp]# ls a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt k.txt l.txt [root@centos7 tmp]#
大括號擴展和文件名的通配符匹配相似,但大括號擴展並不須要文件是存在的。函數
[root@centos7 tmp]# ls [a-n].txt a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt k.txt l.txt [root@centos7 tmp]# ls {a..n}.txt ls: 沒法訪問m.txt: 沒有那個文件或目錄 ls: 沒法訪問n.txt: 沒有那個文件或目錄 a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt k.txt l.txt
大括號也能夠嵌套
如建立目錄測試
[root@centos7 tmp]# mkdir -p ./a{m,n/{1..3},o}x [root@centos7 tmp]# find . -type d . ./amx ./an ./an/1x ./an/2x ./an/3x ./aox [root@centos7 tmp]#
序列表達式中數字以0開頭時,擴展後會在全部數字前添加0以使它們等寬centos7
[root@centos7 tmp]# echo {05..100..5} 005 010 015 020 025 030 035 040 045 050 055 060 065 070 075 080 085 090 095 100
還能夠用在for循環命令中
[root@centos7 tmp]# for i in {1..10..2};do echo $i;done 1 3 5 7 9 [root@centos7 tmp]#
一點小技巧:
#備份 [root@centos7 tmp]# find . -name '*.txt' -exec cp {}{,.bak} \; [root@centos7 tmp]# ls [a-z].txt{,.bak} a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt k.txt l.txt a.txt.bak b.txt.bak c.txt.bak d.txt.bak e.txt.bak f.txt.bak g.txt.bak h.txt.bak i.txt.bak j.txt.bak k.txt.bak l.txt.bak #移動 [root@centos7 tmp]# mv {[a-z].txt.bak,amx} [root@centos7 tmp]# ls amx an aox a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt j.txt k.txt l.txt [root@centos7 tmp]# ls amx/ a.txt.bak b.txt.bak c.txt.bak d.txt.bak e.txt.bak f.txt.bak g.txt.bak h.txt.bak i.txt.bak j.txt.bak k.txt.bak l.txt.bak
shell中以字符~
開頭的單詞(不能被引用)也會被做爲一種擴展方式(或者用在變量賦值等號右邊)。
下面給出部分舉例:
#單詞 擴展結果 ~ $HOME ~+ $PWD ~- $OLDPWD ~user_name #用戶user_name的家目錄
如
[root@centos7 tmp]# echo ${PWD/#$HOME/~} /root/temp/tmp [root@centos7 tmp]# echo "${PWD/#$HOME/~}" ~/temp/tmp [root@centos7 tmp]#
在講語法的時候咱們談到命令替換
(格式爲:$(...)或 `...`),是命令執行與變量操縱的結合。shell運行一個命令,收集其輸出,而後將輸出做爲展開的值。命令替換
的一個問題是命令的當即執行而後等待結果,此過程當中shell沒法傳入輸入。bash使用一個稱爲進程替換
的功能來彌補這些不足,進程替換
其實是命令替換
和管道
的組合,和命令替換
相似,bash運行一個命令,但令其運行於後臺而再也不等待其完成。關鍵在於Bash爲這條命令打開了一個用於讀和寫的管道,而且綁定到一個文件名,最後展開爲結果。進程替換
的格式爲:<(command)
和 >(command)
。其擴展結果是一個文件(文件描述符):
[root@centos7 tmp]# echo <(ls) /dev/fd/63 [root@centos7 tmp]#
因此能夠用查看文件的命令來得到進程的輸出:
[root@centos7 tmp]# cat <(ls) amx an aox a.txt b.txt c.txt d.txt e.txt ...
能夠執行以下兩個命令試對比命令替換
和進程替換
的區別:
#sleep命令結束後才輸出 echo $(ls;sleep 3) #輸出先於sleep執行結束 cat <(ls;sleep 3)
腳本舉例:
#!/bin/bash #進程替換能夠看成文件來使用 #做爲輸入文件 while read line do ARR+=("$line") done < <(seq 100) #做爲輸出文件 echo $((`echo -n ${ARR[*]} > >(tr ' ' '+')`))
執行結果:
[root@centos7 temp]# ./test.sh 5050 [root@centos7 temp]#
在容許任務控制的系統上,bash能夠有選擇地掛起某個前臺進程,並使它在後臺異步地繼續執行。CTRL+Z
可使一個正在運行的前臺進程掛起:
[root@centos7 ~]# sleep 300 ^Z [1]+ 已中止 sleep 300 [root@centos7 ~]#
[1]
中數字1表示第1個後臺進程
內置命令jobs
能夠查看當前有哪些後臺進程:
[root@centos7 ~]# jobs [1]+ 已中止 sleep 300 [root@centos7 ~]#
內置命令bg
可使掛起的進程在後臺繼續運行:
[root@centos7 ~]# bg %1 [1]+ sleep 300 & [root@centos7 ~]#
%1
表示繼續運行第一個後臺進程,程序運行結束後會顯示:
[1]+ 完成 sleep 300
內置命令fg
可使後臺進程返回到前臺繼續運行:
[root@centos7 ~]# fg %1 sleep 300 ^C [root@centos7 ~]#
在交互式shell或腳本中,以控制操做符&
結尾的命令也會被做爲後臺命令異步地執行,當前shell不會等待此命令執行結束,命令的返回碼爲0。
在腳本中使用後臺執行命令時須要注意,若是當前shell先於後臺進程退出,會致使後臺進程也隨之退出(此時並無執行完)。若是須要等待後臺進程退出後父進程才退出,可使用內置命令wait
。
腳本舉例:
#!/bin/bash #定義C段地址數組 c=(1 2 3 4 5) #測試連通性函數 function ping_ip() { ping -c3 10.0.$i.$j &>/dev/null \ || echo "10.0.$i.$j is not used" >>result.txt } #後臺併發測試 for i in ${c[@]} do for j in {1..254} do ping_ip & done done #等待全部後臺進程結束 wait
執行略