中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Shell腳本編程之Bash特性-IO重定向-變量

發布時間:2020-02-25 05:40:50 來源:網絡 閱讀:2275 作者:skypeGNU1 欄目:系統運維

Bash的特性

一、什么是shell?

  人機交互接口大致可分為:GUI(圖形用戶界面)、CLI(命令行接口) 兩種。

命令解釋器或shell程序是一種機制,通過使用它們,每個交互用戶都可以向操作系統發出命令;操作系統也是通過它們,將相應的結果直接返回到用戶。shell的功能只是提供給用戶操作內核的接口。用戶成功的登錄到計算機后(當用戶開始登錄過程時,一個進程將被分配給用戶),操作系統使用戶進程去執行shell。

shell文本接收器可以接收用戶鍵入的命令,文本接收器首先會對鍵入的字符串進行分析解釋,識別出一些特殊符號并做相應處理。注意它只能識別通配符,而不能識別正則表達式。

操作系統通常沒有內置的窗口界面,而是一個簡單的面向字符的界面,用戶輸入一串字符(以“回車鍵”結束);并且操作系統,也輸出一行行字符到屏幕上作為相應結果。用戶登錄進程執行shell,首先shell分析命令行,然后根據環境變量PATH的設置(不會查找當前目錄),查找系統文件目錄,找到一個文件名字或者是一個文件的完全路徑名,當找到文件后,根據其他參數列表,執行該文件。

二、常見的shell

Shell NameA Bit of History
sh(Bourne)  The original shell from early versions ofUNIX.
csh,tcsh, zsh

The C shell, and its derivatives, originally created by Bill Joy of Berkeley UNIX fame. The C shell isprobably the third most popular type of shell after bash and the Korn shell.

ksh, pdksh

The Korn shell and its public domaincousin. Written by David Korn, this is the default shell on many commercialUNIX versions.

bash

The Linux staple shell from the GNU project. bash, or Bourne AgainSHell, has the advantage that thesource code is freely available, and even if it’s not currently running on yourUNIX system, it has probably been ported to it. bash has many similaritiesto the Korn shell.


如何查看當前系統支持的shell類型?

[zbj@localhost ~]$ cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
[zbj@localhost ~]$

三、歷史命令機制(history)

  我們在命令行上鍵入的命令都會緩存至內存中,為了下次開機給用戶保留命令歷史記錄,bash為每個用戶家目錄都創建一個 .bash_history 文件用于保存歷史記錄。 當用戶正常退出終端時,才會把內存中命令記錄緩存保存到 .bash_history文件中。

  正常情況下,歷史命令的讀取與記錄是這樣的:

  • 當我們以 bash 登陸 Linux 主機之后,系統會主動的由家目錄的 ~/.bash_history 讀取以前曾經下過的命令,那么~/.bash_history 會記錄幾筆數據呢?這就與你 bash 的 HISTFILESIZE 這個變量配置值有關了

  • 假設我這次登陸主機后,共下達過 100 次命令,『等我注銷時, 系統就會將 101~1100 這總共 1000 筆歷史命令更新到 ~/.bash_history 當中。』 也就是說,歷史命令在我注銷時,會將最近緩存中的 HISTFILESIZE 筆記錄到我的紀錄文件當中啦!


3.1 history 相關的環境變量

  •  HISTFILE  用于指定保存歷史命令記錄的文件。bash啟動的時候會讀取~/.bash_history文件并載入到內存中,這個變量就用于設置.bash_history文件,bash退出時也會把內存中的歷史回寫到.bash_history文件。

        ~/.bash_history記錄的是前一次登錄所執行過得命令,而至于這一次登錄所執行的命令都被存放在內存中,當你成功登出系統后,這些命令歷史才會被記錄到.bash_history中。

  • HISTFILESIZE  定義了在文件 ~/.bash_history 中保存命令的記錄總數

  • HISTSIZE          定義了 history 命令輸出的記錄數。

  • HISTCONTROL     控制歷史記錄保留的方式

    • ignorespace 以空白字符開頭的命令不記錄

    • ignoredups  忽略重復,連續重復的命令只記錄一次

    • ignoreboth  兩者都生效(ignorespace + ignoredups)

  • HISTTIMEFORMAT  歷史命令記錄格式

使用HISTTIMEFORMAT顯示時間戳

$ export HISTTIMEFORMAT='%F %T '
$ history | more

3.2 相關命令

    bash的history命令管理功能,使得history命令可以回顧,修改和重用之前使用過的歷史命令。 

## 顯示歷史命令
# history      顯示全部歷史
# history N    顯示之前執行過的若干命令,例:history 2 顯示最近執行過的兩條命令

## 清空history緩存
# history -c

## 寫history
# history -w 讓bash將歷史命令立即從內存寫到.bash_history文件
# history -a 將目前新增的 history 歷史命令寫入.bash_history文件


3.3 事件指示器(event designators)

    shell 中!叫做事件提示符,英文是:Event Designators,事件指示器 (event designator) 是一個對歷史列表中某個命令行條目的引用。

!         開始一個歷史命令替換,除非后面緊跟的是空格,制表符,行結束符,"=","(" 。【當使用內建命令shopt開啟了extglob的shell選項】。

!n     會引用history中的第n個命令,比如輸入 !100,就是執行history列表中的第100條命令

    在命令行上,把感嘆號"!"放在雙引號里執行命令會出錯(譯者注:比如說:echo "hello!"). 因為感嘆號被解釋成了一個歷史命令. 然而在一個腳本文件里,這么寫則是正確的,因為在腳本文件里Bash的歷史機制被禁用了。

!n      執行第n個命令
!!      執行上一個命令
!STRING 執行最近一次以STRING開頭的命令

## 執行歷史命令
# !!      運行上一條命令
# !88     運行第88條命令
# !ca     運行上一個包含ca的命令

## 搜索歷史命令
使用ctrl+r搜索歷史中的字符串,重復按ctrl+r可以在歷史命令列表中不斷的向前搜索包含字符串的命令,回車就會執行查找的命令

Shell腳本編程之Bash特性-IO重定向-變量

1.2 重度推薦

Ctrl-r 
有時候,如果你想重新輸入以前輸入過的某條命令怎么辦? 我見過兩種做法:

l   不停的按向上方向鍵,試圖找出那條命令

l   輸入history命令,然后找到那條命令,或者grep一把history命令的輸出

其實, 你有更好的選擇, 那就是按 C-r, 然后輸入你想要的命令中含有的單詞, 就會出現含有這個單詞的命令, 如果它不是你想要的命令, 就繼續按C-r, 知道出現你想要的命令為止.

有的時候你需要在執行一條歷史命令之前編輯它.比如,你可以像下面那樣搜索“httpd”,終端顯示歷史命令“service httpd stop”,選擇它把“stop”改為“start”然后執行它

[: 在命令提示符下按 Ctrl+R , 將會顯示提示符‖reverse-i-search]

 (reverse-i-search)`httpd`: service httpd stop

: 看到你想要的命令后按下左鍵或者右鍵,就可以在執行這條命令之前編輯它了 C-r效果

(reverse-i-search)`ls': ls a b c

Alt-. 
我經常見別人用mkdir long-long-long-name-dir, 再輸入cd, 后面跟那個長的不能再長的目錄名, 這時候我就會告訴他, 其實你輸入完cd, 可以按Alt-.,就可以自動輸入那個長的不能再長的目錄名了. 其實, Alt-.的真正作用就是把上一條命令的最后一個參數輸入到當前命令行非常非常之方便, 強烈推薦. 如果繼續按Alt-.,會把上上條命令的最后一個參數拿過來. 同樣, 如果你想把上一條命令第一個參數拿過來咋辦呢? Alt-0 Alt-.,就是先輸入Alt-0, 再輸入Alt-.. 如果是上上條命令的第一個參數呢? 當然是Alt-0 Alt-. Alt-..


“UNIX系統中命令歷史機制僅適用于以交互式訪問Shell,不能在Shell腳本中使用”這句話如何理解?

就是說 command history 功能(那個按上鍵調出歷史命令的功能),只能在 interactive 模式(交互模式)下使用。運行腳本時腳本缺省處于非交互模式,不能使用命令歷史功能。


四、命令與文件名補全(TAB | 連續2次 TAB TAB)

命令行自動補齊(automatic command line completion)

Bash為linux用戶默認提供了下面的標準補全命令。

  • 變量名補全(Variablename completion)

  • 用戶名補全(Username completion)

  • 主機名補全(Hostname completion)

  • Path路徑補全(Pathname completion)

  • 文件名補全(Filename completion)


命令包括:內部命令和外部命令。內部命令就是shell本身提供的,相當于一個函數的功能。外部命令是某個路徑下的可執行文件。

       執行外部命令需要根據PATH環境變量中指定的路徑進行搜索,按從左至右的順序依次查找,最先找到的即可匹配,并停止查找過程。但是當執行過一次之后,就不會再到PATH路徑下查找了,為了加快查找命令的速度,直接把命令路徑保存在緩存中(hash表),提高查找效率。

[zbj@localhost ~]$ help hash                    # hash是bash內置命令
hash:hash [-lr] [-p pathname] [-dt] [name ...]
    Remember or display program locations.
    
[zbj@localhost ~]$ hash
hits	command
   1	/usr/bin/last
   5	/usr/bin/sort
   1	/usr/bin/rm
   1	/usr/bin/cat
   2	/usr/bin/vim

五、命令別名(alias)

# 設置別名
alias name='command [option] [argument]'

# 取消指定的別名設置
unalias name

# 列出設置的別名
alias

# 轉義別名
alias rm='rm -i'
\rm        # 轉義別名而使用原始的命令

[root@localhost ~]# rm tmp.txt
rm: remove regular file `tmp.txt'? n
[root@localhost ~]# \rm tmp.txt    # \rm,使用 \ 對別名進行轉義

問題思考

1. 怎么取消指定別名?

2. 別名在shell腳本中有效嗎?

3. 怎樣列出所有別名?

4. 怎樣取消所有別名?

5. 怎樣執行ls命令本身,而不是別名?

正常情況下,bash會檢查指令的第一個token是不是別名,若是,則把別名替換成真正的指令。

  • 在shell中定義的別名,僅在當前shell生命周期中生效。通常我們通過命令配置都是在內存中臨時生效的,如果要永久生效,需通過修改程序的配置文件來實現。

  • 別名可以嵌套,但是不會無限遞歸,造成死循環。

每個簡單命令的第一個字token,如果被引用的話就進行是否有設置別名的檢查。如果存在,這個token就被別名的文本替換。別名的名字和替換的文本可能包含任何錯誤的shell輸入,包括shell特殊字符,例外的是別名的名字不可以包含 “=”。 替換的文本的第一個token進行別名的測試,但是對同一個別名已經擴展的token不進行第二次擴展。這樣意味著 ls 可以成為 ls -F,而且Bash不會嘗試遞歸擴展替換的文本。如果別名值的最后一個字符是一個空格或者制表符(TAB),那么跟隨在別名之后的下一個命令會進行別名擴展的檢查。

別名在需要把某個在你系統上存在多個版本的命令指定為默認版本的時候非常有用,或者為命令指定一個默認的選項。別名的另外一個用途是糾正不正確的拼寫。

在shell不是交互的時候,別名不會進行擴展,除非expand_aliases 選項設置成用shopt shell內建命令。

六、通配符(wildcard, gblobbing

[root@localhost ~]# ls *.sh
init_use.sh  mysql_bak.sh

通配符是系統shell層次(level的),由shell負責解釋, 而正則表達式需要相關工具的支持: egrep, awk, vi, perl。      

  • 在文本過濾工具里,都是用正則表達式,比如像awk,sed等,是針對文件的內容的。      

  • 通配符多用在文件名上,比如查找 find,ls,cp,等等。通配用于描述【文件名匹配】,而且必須完整的匹配整個文件名。作用非常單一,所以功能沒有正則表達式牛X。

  通配符是由shell本身處理的(不是由所涉及到命令語句處理的), 它只會出現在命令的“參數”里(它不用在 命令名稱里, 也不用在 操作符上)。當shell在“參數”中遇到了通配符時,shell會將其當作文件名去在磁盤上搜尋可能的匹配:若符合要求的匹配存在,則進行代換(路徑擴展);否則就將該通配符作為一個普通字符傳遞給“命令”,然后再由命令進行處理。總之,通配符 實際上就是一種shell實現的路徑擴展功能。在 通配符被處理后, shell會先完成該命令的重組,然后再繼續處理重組后的命令,直至執行該命令。

  這種支持也叫做 “globbing”(由于歷史原因),允許您通過使用通配符模式一次指定多個文件。Bash 和其它 Linux 命令將通過在磁盤上查找并找到任何與之匹配的文件來解釋這種模式。

  我們回過頭分析上面命令吧:*.sh 實際shell搜索文件,找到了符合條件的文件,命令會變成:ls init_use.sh mysql_bak.sh ,實際在執行ls 時候傳給它的是init_use.sh mysql_bak.sh .

了解了shell通配符,我們現在看下,shell常見通配符有哪一些呢。

*    匹配任意個字符

?    匹配任意單個字符

[]    匹配指定范圍內的任意單個字符

Shell腳本編程之Bash特性-IO重定向-變量

  • 總的來說,正是因為shell中的meta、wildcard有時會和command中的meta相同,為了讓command中的meta不被shell解析以至于改變,就必須用shell quoting來保證其文字不變性

  • 通配符匹配文件名,但是不包含 ”.” 開頭的(所以通配符無法匹配隱藏文件名)。


There are three quoting mechanisms: the escape character, single quotes, and double quotes.

Shell腳本編程之Bash特性-IO重定向-變量


六、快捷鍵(命令行編輯)

    在命令行輸入命令的時候,我們可通過快捷鍵實現命令行編輯。

Ctrl +a :移到命令行首(a字母之首)

Ctrl +e :移到命令行尾(end)

Ctrl +u :從光標處刪除至命令行首

Ctrl +k :從光標處刪除至命令行尾

Ctrl +w : 刪除一個單詞(word)

Ctrl +l:清屏(clear)

Ctrl +c:終止命令 (SIGINT )

Ctrl +z:掛起命令

Ctrl +D:退出 OR  EOF(End Of File)

Ctrl +s:暫停終端傳輸

Ctrl +q:恢復終端傳輸


七、shell(scripts)

  命令的堆積。

八、基本的I/O重定向

     標準輸入、輸出:程序應該有數據的來源端、數據的目的端以及報告問題的地方。程序不必知道它的輸入與輸出背后是什么設備:磁盤上的文件、終端、網絡連接或另一個程序。當程序啟動時,可以預期的是,標準輸出、輸入都已打開,且已準備好供其使用。

     默認的情況下,它們會讀取標準輸入,寫入標準輸出,并將錯誤信息傳遞到標準錯誤輸出,這類程序叫做過濾器。默認的標準輸入、標準輸出以及標準錯誤輸出都是終端。

Shell腳本編程之Bash特性-IO重定向-變量

  那么是誰替執行的程序初始化標準輸入、輸出及錯誤輸出的呢??  系統初始化。

  答案就是在你登錄時,UNIX便將默認的標準輸入、輸出及錯誤輸出安排成你的終端。I/O重定向就是你通過與終端交互,或是在shell腳本里設置,重新安排從哪里輸入或輸出到哪里。I/O重定向是Linux提供的一種多任務協調機制。

基本概念:

  1. I/O重定向通常與FD(File descriptor)有關,shellFD通常為10個,即09; 

  2. 常用FD3個,為0(stdin,STDIN_FILENO 標準輸入)1(stdout,STDOUT_FILENO標準輸出)、2(stderr,STDERR_FILENO標準錯誤輸出),默認與keyboardmonitormonitor關聯; 

  3. 用 來改變讀進的數據信道(stdin),使之從指定的檔案讀進;是 的默認值,因此 與 0<是一樣的;同理,與 1> 是一樣的; 

  4. 用 來改變送出的數據信道(stdout, stderr),使之輸出到指定的檔案; 

  5. IO重定向 中,stdout 與 stderr 的管道會先準備好,才會從 stdin 讀進資料; 

  6. 管道|(pipe line):上一個命令的 stdout(不包括stderr) 接到下一個命令的 stdin

  7. tee 命令是在不影響原本 I/O 的情況下,將 stdout 復制一份到檔案去

  8. bashksh)執行命令的過程:分析命令-變量求值-命令替代(``$( ))-重定向-通配符展開-確定路徑-執行命令; 

  9. ( ) 將 command group 置于 sub-shell 去執行,也稱 nested sub-shell,它有一點非常重要的特性是:繼承父shell的Standard input, output, and error plus any other open file descriptors。 

  10. exec 命令:常用來替代當前 shell 并重新啟動一個 shell,換句話說,并沒有啟動子 shell。使用這一命令時任何現有環境都將會被清除。exec 在對文件描述符進行操作的時候,也只有在這時,exec 不會覆蓋你當前的 shell 環境。

  11. 默認情況下,> 如果原有文件存在,默認操作是覆蓋。如何禁止這種行為呢?

disallow existing regular files to be overwritten by redirection of output.
# set -C        # 關閉這個特性
# set +C        # 開啟


如何把標準輸出stdout, 標準錯誤輸出stderr的數據通通寫到同一個文件中呢?

find  /home -name .bashrc > file.out 2> file.out      # error ,可以達到效果,但是信息相互交錯
find /home -name .bashrc &> file.out                  # right
find /home -name .bashrc > file.out 2>&1              # right

  ... 2>&1 運行一個命令并把它的標準輸出和輸出合并。(嚴格的說是通過復制文件描述符來建立文件描述符,但效果通常是合并了兩個流。

  我們對 2>&1詳細說明一下:2>&1 也就是FD2FD1 ,這里并不是說FD2 的值等于FD1的值,因為是改變送出的數據信道,也就是說把FD2 的 數據輸出通道” 改為FD1 的 數據輸出通道。如果僅僅這樣,這個改變好像沒有什么作用,因為FD2 的默認輸出和FD1的默認輸出本來都是 monitor,一樣的!但是,當FD1 是其他文件,甚至是其他FD 時,這個就具有特殊的用途了。請大家務必理解這一點。 

為何2>&1要寫在后面?
      command > file 2>&1         #  使用 dup2()
      首先是command > file將標準輸出重定向到file中, 2>&1 是標準錯誤拷貝了標準輸出的行為,也就是同樣被重定向到file中,最終結果就是標準輸出和錯誤都被重定向到file中。 
      command 2>&1 >file 
      2>&1 標準錯誤拷貝了標準輸出的行為,但此時標準輸出還是在終端。>file 后輸出才被重定向到file,但標準錯誤仍然保持在終端。

可以考慮一下不同的dup2()調用序列會產生怎樣的文件共享結構。請參考APUE 3.10, 3.12

Shell腳本編程之Bash特性-IO重定向-變量


九、管道(pipe)

     program1 | program2 可將program1的標準輸出修改為program2的標準輸入。管道可以把多個執行中的程序銜接在一起(管道可以使的執行速度比使用臨時文件的程序快上十倍)。構造管道時,應該試著讓每個階段的數據量變的更少,以提高性能。

  管道僅能處理由前面一個命令的標準輸出(standard out

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

裕民县| 古蔺县| 浦东新区| 耒阳市| 雷山县| 定兴县| 新密市| 栾川县| 扎兰屯市| 丹寨县| 和静县| 三明市| 澎湖县| 余干县| 晋宁县| 五原县| 峡江县| 磐安县| 太白县| 安泽县| 姜堰市| 乌兰察布市| 新巴尔虎左旗| 博白县| 永泰县| 乐至县| 海阳市| 门源| 象州县| 昌乐县| 贵定县| 靖江市| 长武县| 镇江市| 千阳县| 五大连池市| 龙南县| 平泉县| 宁南县| 丹凤县| 黔南|