标题：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;
}

课程
Linux shell脚本编程课程大纲：
第1章 shell简介及基础
第2章 变量
第3章 循环结构与流程控制
第4章 函数
第5章 算术运算
第6章 重定向与转向
第7章 高级变量与字符串操作
第8章 正则表达式
第9章 sed编辑器
第10章 awk学习
第11章 文字与图形接口编程
第12章 bash网络编程
第13章 trap陷阱触发
第14章 shell脚本加密与包装
第15章 shell中常用命令介绍
第16章 一些shell技巧
第17章 shell十三问
第18章 综合实战讲解一
第19章 综合实战讲解二