shell如何解析命令行以及eval命令

来源:http://www.cnblogs.com/f-ck-need-u/archive/2017/08/23/7419502.html
-Advertisement-
Play Games

1.1 shell解析命令行 shell讀取和執行命令時的大致操作過程如下圖: 以執行以下命令為例: echo -e "some files:" ~/i* "\nThe date:$(date +%F)\n$name's age is $((a+4))" >/tmp/a.log 假設在執行該命令前, ...


1.1 shell解析命令行

shell讀取和執行命令時的大致操作過程如下圖:

 

以執行以下命令為例:

echo -e "some files:" ~/i* "\nThe date:$(date +%F)\n$name's age is $((a+4))" >/tmp/a.log

假設在執行該命令前,已賦值變數"name=longshuai"和"a=24",於是重定向到/tmp/a.log中的結果為:

some files: /root/inotify.sh /root/inotify.sh.ori
The date:2017-08-14
longshuai's age is 28

(1).讀取輸入的命令行。

(2).解析引用並分割命令行為各個單詞,各單詞稱為token。其中重定向所在的token會被保存下來,直到擴展步驟(5)結束後才進行相關處理,如進行擴展、截斷文件等。

shell中有3種引用方式:反斜線引用、單引號引用和雙引號引用。

◇ 反斜線轉義:使得元字元變為普通的字面字元。但這隻能對反斜線後一個字元進行轉義。

◇ 單引號引用:單引號內的所有字元全部變為字面符號符號。但註意:單引號內不能再使用單引號,即使使用了反斜線轉義也不允許。

◇ 雙引號引用:使雙引號內所有字元變為字面符號,但"\"、"$"、"`"(反引號)除外,如果開啟了"!"引用歷史命令時,則感嘆號也除外。

解析引用後,於是就可以將命令行進行單詞分割,分割後的每一部分都稱為一個token。分隔時,不僅分割單個命令,還分割命令列表,所以分隔符包括:空格、tab、分號、管道符號、&、&&、||、重定向符號、圓括弧等。

於是上述命令分割為以下幾個token:

如果分割時發現了管道符號,或者是命令列表等組合了多個命令的情況,則每個命令都的token都相互獨立。

(3).檢查命令行結構。主要檢查是否有命令列表、是否有shell編程結構的命令,如if判斷命令、迴圈結構的for/while/select/until,這些命令屬於保留關鍵字,需要特殊處理。

(4).對第一個token進行別名擴展。如果檢查出它是別名,則擴展後回到(2)再次進行token分解過程。

(5).進行各種擴展。擴展順序為:大括弧擴展;波浪號擴展;參數、變數和命令替換、算術擴展(如果系統支持,此步還進行進程替換);單詞拆分;文件名擴展。

不同引號的引用方式,將改變擴展的起始步驟,正如上圖所畫,沒有任何引號時將從頭到尾全部擴展,使用單引號時將完全不會進行任何擴展,使用雙引號時將從變數替換開始繼續擴展。

①大括弧擴展:如/tmp/{a,b}.log擴展為/tmp/a.log和/tmp/b.log。

②波浪號擴展:擴展為家目錄。如root用戶下的~/.ssh擴展為/root/.ssh。

③變數擴展:即操作和替換變數值。如$a替換為它的值24,${name:-longshuai}替換為longshuai。

④命令替換:此過程將執行命令替換中的命令,並將結果替換到token的對應位置處。

⑤進程替換:將進程的執行結果替換到對應位置。類似於命令替換。替換格式為"<(cmd_list)"和">(cmd_list)",例如"cat <(cat /etc/hosts)"。redhat系列應該都支持進程替換。

⑥算術擴展:計算算術值,並將計算結果替換到對應位置處。例如$((a+4))替換為28。

經過以上幾種擴展後,得到如下結果:

⑦單詞拆分:掃描變數擴展、命令替換和算術擴展的結果,對非引號內的結果按照$IFS的值對這些結果進行單詞分割。

註意,如果沒有進行擴展,或者擴展結果使用引號包圍了,則不會進行此步的單詞拆分。

預設情況下,$IFS值為"   \t\n",所以擴展結果中每遇到空格、製表符、換行符都將被分割為兩個單詞。

這一步其實很容易犯錯,典型的是test命令。例如變數name="Ma longshuai",則test $name == "longshuai"將報錯,因為變數擴展後該語句變為test Ma longshuai == "longshuai",由於是變數替換,所以隨後進行單詞拆分,使得Ma和longshuai被拆分為兩個單詞,但實際上它們共同組成變數name的值。

所以,為了正確操作變數替換和命令替換,儘量將它們使用引號包圍。例如test "$name" == "longshuai",這時將不會進行單詞拆分。

⑧文件名擴展:對每個token進行搜索,將搜索"*"、"?"和"["符號,搜索到了將進行文件名擴展。例如將上面的"/root/i*"擴展為"/root/inotify.sh /root/inotify.sh.ori"。

(6).引號去除。經過上面的過程,該擴展的都擴展了,不需要的引號在此步就可以去掉了。

所以得到如下結果。

(7).搜索和執行命令。

單詞分割後,複雜的命令行將由各個簡單命令結構組成。於是可以搜索每個簡單命令結構的第一個token中的命令,同時還帶有一系列命令選項。例如上面的"echo"和"-e"。

如果命令中不含任何斜杠:

①則先判斷是否有此名稱的shell function存在,如果有則調用它,否則進行下一步搜索。

②判斷該命令是否為bash內置命令,如果是則執行它,否則進行下一步搜索。

③從$PATH的路徑下搜索該命令,如果搜索到了,則執行,否則報錯。

如果命令中包含一個或多個斜杠,則進行相對路徑擴展、絕對路徑查找,找到了則執行,否則報錯。

(8).返回退出狀態碼。

1.2 eval命令

正常情況下,當搜索到命令時將會執行命令,但如果搜索到的命令為eval時,則處理方式有所不同。

它的語法格式為:

eval command arguments

按照前文所述shell解析過程,將最終得到eval command和一系列擴展後的選項、參數,當搜索命令時,搜索到的結果為eval命令,於是eval命令將除了eval命令(以及eval的選項)的所有token再次傳遞給shell進行二次解析。但重定向所在token除外,因為重定向token早已被shell保存下來,所以不會再次截斷文件。

也就是說,"command arguments"被當作eval命令的參數,被傳遞給shell進行解析、執行。

執行過程如下圖所示:

使用示例來說明:

[root@xuexi ~]# a=24;name='long$a'     # 註意,使用的是單引號,禁止$a被擴展

如果直接執行echo $name,則結果為"long$a",但如果執行eval echo $name,結果將是"long24"。

[root@xuexi ~]# eval echo $name
long24

首先shell按照正常過程解析,在變數替換時由於使用了單引號,所以$name第一次變數替換的結果為"long$a",直到命令搜索時發現搜索到的命令是eval命令,執行eval命令,該命令將其參數"echo long$a"再次傳遞給shell,相當於在標準輸入中輸入了"echo long$a",於是shell進行二次解析,這次的變數替換將$a替換為24,最後搜索命令發現是echo命令,於是最終得到"long24"。

關於eval,更多的用法是間接變數$$var的用法,在bash shell中需要在第一個$前加上反引號,即\$$var,這麼做的原因是顯然的:防止第一次shell解析時被當作特殊變數"$$"被擴展。

[root@xuexi ~]# a=b
[root@xuexi ~]# b=haha

[root@xuexi ~]# eval echo \$$a
haha

 

註:本文並非一定准確,只是根據man bash總結而來。如有錯誤,請明確指出。多謝

 

回到系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html

轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/7419502.html

註:若您覺得這篇文章還不錯請點擊下右下角的推薦,有了您的支持才能激發作者更大的寫作熱情,非常感謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在Android程式內部, startActivity藉助Intent來啟動一個子Activity ...
  • 1. 同時滿足多個關鍵字 grep "word1" file_name | grep "word2" | grep "word3" 2. 滿足任意關鍵字 grep -e "word1" -e "word2" -e "word3" file_name 3. 排除關鍵字 grep -v "word" f ...
  • 一、環境及安裝版本: centos6.5、Nginx1.4.7、keepalived1.3.2 虛擬IP 真是IP Nginx埠 主從分配 10.0.90.215 10.0.90.217 80 MASTER 10.0.90.215 10.0.90.218 80 BACKUP 二、Nginx安裝 分 ...
  • 運維之Linux基礎(二) 1. file 命令基期用法 2. 文件系統 Linux的文件系統結構是樹狀結構,所有的文件都在/root跟目錄下 /boot:系統啟動相關的文件, 如:內核、initrd,以及grub(bootloadser) /dev:設備文件 塊設備:隨機訪問,按數據塊進行訪問的 ...
  • 分析前準備 # 進入工作目錄 cd example_PE250 上一節回顧:我們獲得了OTU序列的進化分析、同時計算Alpha和Beta多樣性值。 本節是最後一節,我們對物種進行分類統計,篩選高豐度結果用於進化樹展示,和其它用於R統計分析的結果生成 19. 按物種分類級別分類彙總 OTU表中最重要的 ...
  • 因為CentOS升級到7之後,發現無法使用iptables控制Linuxs的埠,因為CentOS 7使用firewalld代替了原來的iptables。下麵記錄如何使用firewalld開放Linux埠: 1、查詢某埠是否開放 2、永久開啟某埠 firewall-cmd --zone=pub ...
  • 分析前準備 # 進入工作目錄 cd example_PE250 上一節回顧:我們的OTU獲得了物種註釋,並學習OTU表的各種操作————添加信息,格式轉換,篩選信息。 接下來我們學習對OTU序列的進化分析、同時計算Alpha和Beta多樣性值。 16. 進化樹構建 進化樹是基於多序列比對的結果,可展 ...
  • 本節課程,需要先完成《擴增子分析解讀》系列之前的操作 1質控 實驗設計 雙端序列合併 2提取barcode 質控及樣品拆分 切除擴增引物 3格式轉換 去冗餘 聚類 4去嵌合體 非細菌序列 生成代表性序列和OTU表 分析前準備 # 進入工作目錄 cd example_PE250 上一節回顧:我們學習了 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...