Shell編程

shell 是作業系統的最外層。shell 合併程式語言以控制進程和檔案,以及啟動和控制其它程式。shell 通過提示您輸入,向作業系統解釋該輸入,然後處理來自作業系統的任何結果輸出來管理您與作業系統之間的互動。

基本概述

shell 提供了與作業系統通信的方式。此通信以互動的方式(來自鍵盤的輸入立即操作)或作為一個 shell 腳本執行。shell 腳本是 shell 和作業系統命令的序列,它存儲在檔案中。

當登錄到系統中時,系統定位要執行的 shell 的名稱。在它執行之後,shell 顯示一個命令提示符。普通用戶的此提示符通常是一個 $(美元符)。當提示符下輸入命令並按下 Enter 鍵時,shell 對命令進行求值,並嘗試執行它。取決於命令說明,shell 將命令輸出寫到螢幕或重定向到輸出。然後它返回命令提示符,並等待您輸入另一個命令。

命令行是輸入所在的行。它包含 shell 提示符。每行的基本格式如下:

$ 命令參數(一個或多個)

shell 視命令行的第一個字(直到第一個空白空格)為命令,所有後繼字為自變數。

在Windows環境下,不論是使用Visual C++還是Delphi或是其他一些軟體開發工具開發的應用程式,儘管存在著差別,但有一點是相同的:都是運行於Windows作業系統之下的。在程式開發過程中也經常要在自己的應用程式中加入一些Windows系統本身就有的功能,比如檔案的拷貝、刪除、查找以及運行程式等等。而這些功能在Windows作業系統下都是具備的,顯然如果能直接從系統中調用這些功能將不僅僅減少程式的大小和開發人員的工作量,而且由於是直接通過作業系統來完成這些功能,將會大大減小這部分程式出現異常錯誤的機率。Windows系統雖說也存在不少錯誤,但常用功能的錯誤還是比較少的,而且通過補丁程式可以更低限度減少系統錯誤,因此程式設計師可以將調試檢錯的注意力放在應用程式的其他地方,對於調用系統功能這部分代碼則可以不必投入太大的精力去調試,因為這部分調試的工作在作業系統發布的時候就已經由微軟做好了。本文通過外殼編程,實現了搜尋檔案、運行程式、控制工具條、最大最小化視窗的功能。

實現方法

前面所說的直接使用Windows作業系統部分功能的編程方法就是針對Windows作業系統外殼的編程,可以通過對作業系統提供的幾個編程接口對作業系統的部分功能進行調用,甚至可以按照自己的意圖在應用程式中對部分功能進行修改、擴展。但這方面的資料介紹不是特別多,講的也大都語焉不詳,而且用通常的編程方法去進行外殼編程是非常麻煩的,動輒就要對相關的結構對象進行設定,而這樣的結構里的數據成員少則十來個多則幾十個,因此配置起來非常煩瑣,下面就以一個比較簡單的外殼操作--拷貝檔案進行舉例說明:

…… SHFILEOPSTRUCT FileOp; //外殼的檔案操作結構 FileOp.hwnd=m_hWnd; //設定句柄 //設定操作方式,拷貝用FO_COPY,刪除用 FO_DELETE FileOp.wFunc=FO_COPY; FileOp.pFrom=m_source; //源檔案路徑 FileOp.pTo=m_detect; //目標檔案路徑 FileOp.fFlags=FOF_ALLOWUNDO; //允許恢復 FileOp.hNameMappings=NULL; FileOp.lpszProgressTitle=strTitle; //設定標題 SHFileOperation(&FileOp); //執行外殼拷貝 if(FileOp.fAnyOperationsAborted) //監測有無中止 TRACE("An Operation was aborted!!!\n"); ……

上述代碼實現起來雖然效果還是不錯的,但然實現起來卻是比較麻煩的,這僅僅是一個比較簡單的外殼操作,對於一些比較複雜的外殼操作比如系統托盤、任務條等等的編程,更是尤為嚴重,而且象此類編程,MFC里並沒有提供封裝好的程式類庫,提供的只有系統的WinAPI 應用程式接口,因此在程式開發過程中往往會有一種在進行SDK編程的感覺。

COM (Component Object Model,組件對象模型)是Microsoft創建的一種二進制和網路標準,也是Microsoft大力推廣並已取得廣泛認可的一種組件標準。在COM標準中,COM對象被很好的封裝起來,客戶無法訪問對象的實現細節,提供給用戶的唯一的訪問途徑是通過COM接口來訪問。對於COM接口有兩方面的含義:首先它是一組可供調用的函式,由此客戶可以讓該對象做某些事情;其次,也是更為重要的,接口是組件及其客戶程式之間的協定。也就是說接口不但定義了可用什麼函式,也定義了當調用這些函式時對象要做什麼。Windows作業系統本身作為一個大的COM組件對象,也提供了一些必要的COM接口給客戶程式,因此我們可以通過這些COM接口來直接對Windows外殼進行編程。

在程式進行正式編寫設計之前有一點是肯定的:程式里需要用到COM接口,要對COM對象進行操作。因此首先要加入初始化COM和終止COM的代碼。一般是在應用程式類的InitInstance()函式的開始處和返回前添加初始化COM和終止COM代碼的:

…… CoInitialize(NULL); //初始化COM …… CoUninitialize(); //終止COM代碼 ……

以上兩個函式在MFC程式和非MFC程式中都可以很好的使用。另外,如果程式框架是以MFC為基礎的,那么只需簡單的調用AfxOleInit()函式就可以達到同樣的目的。而且不必顯式調用終止COM的代碼。在COM標準中,訪問COM對象的唯一途徑是COM接口,因此在編寫操縱Windows 系統外殼程式首先要得到其提供的COM接口。所用的COM接口是IShellDispatch,它是從IDispatch接口派生來的,在VC安裝目錄的VC98\Include\Exdisp.h頭檔案中有定義,下面節選了一些將要用到的接口定義:

…… EXTERN_C const IID IID_IShellDispatch; #if defined(__cplusplus) && !defined(CINTERFACE) interface DECLSPEC_UUID("D8F015C0-C278-11CE-A49E-444553540000") IShellDispatch : public Idispatch { public: …… virtual HRESULT STDMETHODCALLTYPE MinimizeAll( void) = 0; virtual HRESULT STDMETHODCALLTYPE UndoMinimizeALL( void) = 0; virtual HRESULT STDMETHODCALLTYPE FileRun( void) = 0; virtual HRESULT STDMETHODCALLTYPE CascadeWindows( void) = 0; virtual HRESULT STDMETHODCALLTYPE TileVertically( void) = 0; virtual HRESULT STDMETHODCALLTYPE TileHorizontally( void) = 0; virtual HRESULT STDMETHODCALLTYPE ShutdownWindows( void) = 0; virtual HRESULT STDMETHODCALLTYPE Suspend( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetTime( void) = 0; virtual HRESULT STDMETHODCALLTYPE TrayProperties( void) = 0; virtual HRESULT STDMETHODCALLTYPE Help( void) = 0; virtual HRESULT STDMETHODCALLTYPE FindFiles( void) = 0; virtual HRESULT STDMETHODCALLTYPE FindComputer( void) = 0; }; ……

該接口在CoCreateInstance()函式創建COM對象時將會得到指向其的指針,通過這個函式客戶程式可以避免顯式同類廠打交道,其實該函式內部也調用了CoGetClassObject()函式來獲取COM對象的類廠,只不過它把通過類廠創建對象的過程封裝起來了,只需用戶指定對象類的CLSID和待輸出的接口指針及接口ID,顯然這樣直接創建COM對象是非常便捷的,在獲取到COM對象指針之後就可以通過這個指針去訪問調用COM對象里的方法來實現Windows 外殼的種種功能調用了。下面是實現該功能的部分關鍵代碼:

…… HRESULT sc;//返回結果 IShellDispatch *pShellDisp = NULL; //初始化接口指針 //直接創建COM對象 sc = CoCreateInstance( CLSID_Shell,//指定待創建的COM對象標識符 NULL, //指定被聚合時的外部對象的接口指針 CLSCTX_SERVER, //指定組件類別,可以指定進程內組件進程外組件或者進程內控制對象。 IID_IDispatch, //指定接口ID,需要注意的是這裡指的是待 //創建的COM對象的接口ID,而非類廠對象的接口標識符 (LPVOID *) &pShellDisp );//存放函式返回的對象的接口指針 /* 在上述代碼中,CoCreateInstance首先調用CoGetClassObject函式創建類廠對象,然後用得到的類廠對象的接口指針創建真正的COM對象,最後把類廠對象釋放並返回,這樣就很好的把類廠禁止起來,使用戶用起來更為簡單。*/ if( FAILED(sc) )//必須用FAILED 或SUCCECCED來判斷COM對象是否創建成功 return; pShellDisp->FindFiles(); //調用COM對象里的方法 pShellDisp->Release(); //釋放申請到的接口指針 ……

在這裡通過pShellDisp接口指針調用了COM對象的FindFiles()方法去進行查找檔案的系統外殼操作。同樣,可以根據實際需要靈活調用回響的方法來執行相應的外殼操作,主要有以下幾個方法:MinimizeAll:所有視窗最小化、UndoMinimizeALL:恢復視窗最小化、 FileRun:開始選單的"運行…"、CascadeWindows:層疊視窗、TileVertically:垂直平鋪、TileHorizontally:水平平鋪、ShutdownWindows:關閉Windows、Suspend 掛起計算機、SetTime:設定時間、TrayProperties:系統列屬性、Help Windows:幫助、FindFiles:查找檔案、FindComputer:查找計算機等。

這些接口均在VC安裝目錄的VC98\Include\Exdisp.h頭檔案中有定義,可以通過對該檔案的查看來編寫回響的外殼操作代碼。

編程步驟

1、 啟動Visual C++6.0,生成一個Win32應用程式,項目命名為"Shell";

2、 添加應用程式圖示資源APP_ICON和對話框資源DLG_MAIN,對話框界面按上圖一設計;

3、 使用Class Wizard為對話框上的各個按鈕添加滑鼠單擊處理函式;

4、 添加代碼,編譯運行程式。

常用技巧

1. 字元串的截取

shell字元串的截取的問題:

一、Linux shell 截取字元變數的前8位,有方法如下:

1) expr substr “$a” 1 8

2) echo $a|awk ‘{print substr(,1,8)}’

3) echo $a|cut -c1-8

4) expr $a : ‘\(.\\).*’

5) echo $a|dd bs=1 count=8 2>/dev/null

二、按指定的字元串截取

1) 第一種方法:

${varible##*string} 從左向右截取最後一個string後的字元串

${varible#*string}從左向右截取第一個string後的字元串

${varible%%string*}從右向左截取最後一個string後的字元串

${varible%string*}從右向左截取第一個string後的字元串

“*”只是一個通配符可以不要

例子:

$ MYVAR=foodforthought.jpg

$ echo ${MYVAR##*fo}

rthought.jpg

$ echo ${MYVAR#*fo}

odforthought.jpg

2) 第二種方法:${varible:n1:n2}:截取變數varible從n1到n2之間的字元串。

可以根據特定字元偏移和長度,使用另一種形式的變數擴展,來選擇特定子字元串。試著在 bash 中輸入以下行:

$ EXCLAIM=cowabunga

$ echo ${EXCLAIM:0:3}

cow

$ echo ${EXCLAIM:3:7}

abunga

這種形式的字元串截斷非常簡便,只需用冒號分開來指定起始字元和子字元串長度。

三、按照指定要求分割:

比如獲取後綴名

ls -al | cut -d “.” -f2

2. 大小寫轉換

echo $uppercase |tr [A-Z] [a-z]

echo $lowercase |tr [a-z] [A-Z]

編程過程

///////////////////////////////////// #define INC_OLE2 #define WIN32_LEAN_AND_MEAN #define STRICT #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <shlguid.h> #include <exdisp.h> #include “taskbar.h” #include “resource.h” // data static WNDPROC g_pfnOldProc; static HWND g_hwndButton=NULL; static HWND g_hDlg=NULL; static HINSTANCE g_hInstance; static HICON g_hIconLarge; static HICON g_hIconSmall; // functions static VOID OnRunPrograms( VOID ); static VOID OnFindFiles( VOID ); static VOID OnMinimizeAll( VOID ); static VOID OnUndoMinimize( VOID ); static VOID OnTaskbarProperties( VOID ); static VOID OnAddTab( HWND ); static VOID OnDeleteTab( VOID ); static VOID OnInitDialog( HWND ); static VOID OnButtonActivation( VOID ); // callbacks LRESULT CALLBACK APP_DlgProc( HWND, UINT, WPARAM, LPARAM ); LRESULT CALLBACK ButtonProc( HWND, UINT, WPARAM, LPARAM ); INT APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevious, LPSTR lpsz, INT iCmd ) { BOOL b; g_hIconLarge = (HICON) LoadImage( hInstance, “APP_ICON”, IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXICON), 0 ); g_hIconSmall = (HICON) LoadImage( hInstance, “APP_ICON”, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CXSMICON), 0 ); // initialize OLE libraries CoInitialize(NULL); InitCommonControls(); // run main dialog g_hInstance = hInstance; b = DialogBox( hInstance, “DLG_MAIN”, NULL, (DLGPROC)APP_DlgProc ); // exit DestroyIcon( g_hIconLarge ); DestroyIcon( g_hIconSmall ); // free the objects used by ITaskbarList DestroyWindow( g_hwndButton ); OnDeleteTab(); CoUninitialize(); return b; }LRESULT CALLBACK APP_DlgProc( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam ) { switch( uiMsg ) { case WM_INITDIALOG: OnInitDialog( hDlg ); break; case WM_COMMAND: switch( wParam ) { case IDC_FINDFILES: OnFindFiles(); return 1; case IDC_RUNPROGRAMS: OnRunPrograms(); return 1; case IDC_MINIMIZE: OnMinimizeAll(); return 1; case IDC_UNDOMINIMIZE: OnUndoMinimize(); return 1; case IDC_PROPERTIES: OnTaskbarProperties(); return 1; case IDC_ADDTAB: OnAddTab( hDlg ); return 1; case IDC_DELETETAB: OnDeleteTab(); return 1; case IDCANCEL: EndDialog( hDlg, FALSE ); return 0; } break; } return 0; } VOID OnFindFiles( VOID ) { HRESULT sc; IShellDispatch *pShellDisp = NULL; sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER, IID_IDispatch, (LPVOID *) &pShellDisp ); if( FAILED(sc) ) return; pShellDisp->FindFiles(); pShellDisp->Release(); return; } VOID OnTaskbarProperties( VOID ) { HRESULT sc; IShellDispatch *pShellDisp = NULL; sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER,IID_IDispatch, (LPVOID *) &pShellDisp ); if( FAILED(sc) ) return; pShellDisp->TrayProperties(); pShellDisp->Release(); return; } VOID OnRunPrograms( VOID ) { HRESULT sc; IShellDispatch *pShellDisp = NULL; sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER, IID_IShellDispatch, (LPVOID *) &pShellDisp ); if( FAILED(sc) ) return; pShellDisp->FileRun(); pShellDisp->Release(); return; } VOID OnMinimizeAll( VOID ) { HRESULT sc; IShellDispatch *pShellDisp = NULL; sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER, IID_IDispatch, (LPVOID *) &pShellDisp ); if( FAILED(sc) ) return; pShellDisp->MinimizeAll(); pShellDisp->Release(); return; } VOID OnUndoMinimize( VOID ) { HRESULT sc; IShellDispatch *pShellDisp = NULL; sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER, IID_IDispatch, (LPVOID *) &pShellDisp ); if( FAILED(sc) ) return; pShellDisp->UndoMinimizeALL(); pShellDisp->Release(); return; } VOID OnInitDialog( HWND hDlg ) { // set the icons (T/F as to Large/Small icon) g_hDlg = hDlg; SendMessage( hDlg, WM_SETICON, FALSE, (LPARAM)g_hIconSmall ); SendMessage( hDlg, WM_SETICON, TRUE, (LPARAM)g_hIconLarge ); } VOID OnAddTab( HWND hWnd ) { static BOOL g_bFirstTime=TRUE; HRESULT sc; ITaskbarList *pDisp = NULL; sc = CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_SERVER, IID_ITaskbarList, (LPVOID *) &pDisp ); if( FAILED(sc) ) return; // call the first time only if( g_bFirstTime ) { g_bFirstTime = FALSE; pDisp->HrInit(); // create a new button window g_hwndButton = CreateWindow( “button”, “My Button”, WS_CLIPSIBLINGS|BS_PUSHBUTTON,0, 0, 58, 14, hWnd, NULL, g_hInstance, NULL ); g_pfnOldProc = (WNDPROC) SubclassWindow( g_hwndButton, ButtonProc ); } pDisp->AddTab( g_hwndButton ); pDisp->Release(); return; } VOID OnDeleteTab( VOID ) { HRESULT sc; ITaskbarList *pDisp = NULL; sc = CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_SERVER, IID_ITaskbarList, (LPVOID *) &pDisp ); if( FAILED(sc) ) return; pDisp->DeleteTab( g_hwndButton ); pDisp->Release(); return; } LRESULT CALLBACK ButtonProc( HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ) { switch( uiMsg ) { case WM_NCACTIVATE: if( wParam==TRUE ) OnButtonActivation(); break; } return CallWindowProc( g_pfnOldProc, hwnd, uiMsg, wParam, lParam ); } VOID OnButtonActivation( VOID ) { HMENU hmenu; RECT r; LONG x, y; // get some window handles HWND h0=FindWindow(“Shell_TrayWnd”, NULL ); HWND h1=FindWindowEx(h0,NULL,”RebarWindow32″, NULL); HWND h2=FindWindowEx(h1,NULL,”MSTaskSwWClass”, NULL); HWND h3=FindWindowEx(h2,NULL,”SysTabControl32″, NULL); GetWindowRect( h3, &r ); // get the currently selected button and // create a new popup menu hmenu = CreatePopupMenu(); INT i=TabCtrl_GetCurSel( h3 ); if( i==-1 ) { AppendMenu( hmenu, MF_STRING, IDC_DELETETAB,”&Close” ); } else { AppendMenu( hmenu, MF_STRING, IDC_MINIMIZE,”&Minimize All” ); AppendMenu( hmenu, MF_STRING, IDC_UNDOMINIMIZE,”&Undo Minimize All” ); AppendMenu( hmenu, MF_SEPARATOR, 0, NULL ); AppendMenu( hmenu, MF_STRING, IDC_PROPERTIES,”&Taskbar Properties” ); } // set and immediately reset its size to get // the current width and height LONG l = TabCtrl_SetItemSize( h3, 0, 0 ); TabCtrl_SetItemSize( h3, LOWORD(l), HIWORD(l) ); // have the menu to appear just above the button if( i==-1 ) { POINT pt; GetCursorPos( &pt ); x = pt.x; y = pt.y; } else { x = r.left + LOWORD(l)*i+3; y = GetSystemMetrics(SM_CYSCREEN)-(HIWORD(l)+1); } TrackPopupMenu( hmenu, TPM_BOTTOMALIGN, x, y, 0, g_hDlg, 0); DestroyMenu( hmenu ); return; }

課程大綱

第1章 簡介及基礎

shell簡介及基礎

shell是什麼,為什麼要學習shell

shell發展史及分類

bash功能簡介

部署設定bash環境

shell腳本組成、運行模式及執行方法

bash排錯方法

父shell和子shell

常用快捷鍵

第2章 變數

變數分類

內部變數

預定義變數

自定義變數及基本用法

數組

特殊字元

別名

Here Document

列印特殊字元

第3章 循環結構與流程控制

if條件判斷

case條件判斷

for循環

while循環

until循環

select命令

break和continue

第4章 函式

函式用法

函式作用範圍

參數使用

建立函式館

遞歸函式

第5章 算術運算

算術式簡介

算術擴展

利用expr做算術運算

使用$[]做算術運算

使用內置變數declare、let做算術運算

利用bc做浮點運算

進制轉換

第6章 重定向與轉向

檔案代碼

操作檔案

輸入輸出轉向

轉向附加

標準錯誤伴隨輸出轉向

Here Document轉向

第7章 高級變數與字元串操作

變數擴展:測試存在性及空值

變數擴展:取字元串切片,字元串長度

變數擴展:對比樣式

變數擴展:取變數名稱列表,數組索引列表

命令替換

第8章 正則表達式

入門介紹

元字元

字條轉義

重複

字元類

分支條件

反義

分組

後向引用

零寬斷言與負向零寬斷言

貪婪與懶惰

注釋

處理選項

平衡組/遞歸匹配

第9章 sed編輯器

sed介紹

sed基本語法

sed調用方式

sed高級用法

第10章 awk學習

awk原理介紹

awk基本語法

awk調用方式

awk循環語句

awk函式

awk數組

awk的BEGIN和END模式

awk數學運算和字元串操作

awk重定向輸出

awk與bash之間傳參調用

awk調試方法

第11章 文字與圖形接口編程

dialog文本接口編程

xdialog圖形接口編程

第12章 bash網路編程

bash網路轉向

遠程執行命令

expect與自動登錄

第13章 trap陷阱觸發

信號signal

trap運用

第14章 shell腳本加密與包裝

加密shell腳本

生成二進制執行檔

第15章 shell中常用命令介紹

grep命令詳解

find與xargs

sort和uniq命令詳解

cut命令詳解

curl與wget命令詳解

cat、tac與rev

tr命令詳解

paste命令詳解

join命令詳解

第16章 一些shell技巧

利用腳本修改密碼

判斷奇偶

添加行號與刪除行號

刪除行首空格,刪除重複行

合併行操作

逐行讀取操作

字元與ASCII碼轉換操作

連線mysql資料庫操作

第17章 shell十三問

PS1和CR的關係

echo知多少

“”(雙綽號)與”(單引號)差在哪兒

export前後差在哪兒

exec跟source差在哪兒

()與{}差在哪兒

$(())和$()、${}差在哪兒

$@和$*差在哪兒

&&和||差在哪兒

>和<差在哪兒>

你要if還是case

for what?while和until差在哪兒?

[^ ]和[! ]差在哪兒

第18章 綜合實戰講解一

系統信息收集腳本

備份腳本

日誌切割腳本

nagios監控外掛程式腳本

發郵件腳本

第19章 綜合實戰講解二

系統初始化腳本

基礎軟體安裝腳本

iptables腳本

線上操作記錄審核腳本

文本完整性審核腳本

kickstart配置腳本

相關詞條

相關搜尋

熱門詞條

聯絡我們