很多 Shell 命令都是可以附帶選項和引數的,不同的選項和引數也使得命令的功能細節有所差異。
Shell 命令附帶引數的例子:
-
cd demo
命令表示進入當前目錄下的 demo 目錄,其中demo
就是 cd 命令的引數。
-
echo "123xyz"
命令表示輸出字串併換行,其中"123xyz"
就是 echo 命令的引數。
Shell 命令附帶選項的例子:
ls -l
命令用來顯示當前目錄下的所有檔案以及它們的詳細資訊,其中
-l
就是 ls 命令的選項。
echo -n "http://c.biancheng.net/shell/"
表示在輸出字串後不換行,其中
-n
是 echo 命令的選項,
"http://c.biancheng.net/shell/"
是 echo 命令的引數。
有些命令的選項後面也可以附帶引數:
-
getsum -s 1 -e 100
命令用來計算從 1 累加到 100 的和,其中-s
和-e
是 getsum 命令的選項,1
和100
分別是-s
和-e
選項的引數。
-
read -n 1 sex
命令用來讀取一個字元並賦值給 sex 變數,其中-n
是 read 命令的選項,1
是-n
選項的引數,sex
是 read 命令的引數。
你是否對這些形形色色的選項和引數感到好奇?你是否想知道它們在底層是如何實現的?你是否也想自己動手對它們進行解析?本節就來給你揭曉答案!
死磕這個細節並不是閒得無聊,它能幫助我們理解命令的真正含義。好了,廢話不多說,讓我們趕緊轉入正題吧。
上節我們講到,一個 Shell 內建命令就是一個內部的函數,一個外部命令就是一個應用程式。內建命令後面附帶的所有資料(所有選項和引數)最終都以引數的形式傳遞給了函數,外部命令後面附帶的所有資料(所有選項和引數)最終都以引數的形式傳遞給了應用程式。
也就是說,不管是內建命令還是外部命令,它後面附帶的所有資料都會被“打包”成引數,這些引數有的傳遞給了函數,有的傳遞給了應用程式。
有程式設計經驗的讀者應該知道,C語言或者 C++ 程式的入口函數是
int main(int argc, char *argv[])
,傳遞給應用程式的引數最終都被 main 函數接收了。從這個角度看,傳遞給應用程式的引數其實也是傳遞給了函數。
有了以上認知,我們就不用再區分函數和應用程式了,我們就認為:
不管是內建命令還是外部命令,它後面附帶的資料最終都以引數的形式傳遞給了函數。實現一個命令的一項重要工作就是解析傳遞給函數的引數。
注意,命令後面附帶的資料並不是被合併在一起,作為一個引數傳遞給函數的;這些資料是由空格分隔的,它們被分隔成了幾份,就會轉換成幾個引數。例如
getsum -s 1 -e 100
要向函數傳遞四個引數,
read -n 1 sex
要向函數中傳遞三個引數。
並且,命令後面附帶的資料都是“原汁原味”地傳遞給了函數,比如
getsum -s 1 -e 100
要傳遞的四個引數分別是 -s、1、-e、100,減號
-
也會一起傳遞過去,在函數內部,減號
-
可以用來區分該引數是否是命令的選項。
至於在函數內部如何解析這些引數,對於外部命令來說那就是 C/C++ 程式設計師的工作了,這裡不再過多贅述,只給出演示程式碼。
上節我給大家演示了一個 getsum 程式,本節依然使用該程式演示引數的解析,只是對程式碼進行了微調。
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int start = 0;
int end = 0;
int sum = 0;
int opt;
char *optstring = ":s:e:";
//分析接收到的引數
while((opt = getopt(argc, argv, optstring))!= -1){
switch(opt){
case 's': start = atoi(optarg); break;
case 'e': end = atoi(optarg); break;
case ':': puts("Missing parameter"); exit(1);
}
}
//檢測引數是否有效
if(start<0 || end<=start){
puts("Parameter error"); exit(2);
}
//列印接收到的引數
printf("Received parameters: ");
for(int i=0; i<argc; i++){
printf("%s ", argv[i]);
}
printf("n");
//計算累加的和
for(int i=start; i<=end; i++){
sum+=i;
}
printf("sum=%dn", sum);
return 0;
}
第 11~20 行是解析引數的關鍵程式碼,getopt.h 標頭檔案中的 getopt() 函數是值得重點研究的,有了該函數我們就不用自己去解析引數了,省了很大的力氣。
第 27~32 行將接收到的引數列印出來,以便讀者更好地觀察。
根據上節給出的辦法就可以執行 getsum 命令:
[[email protected] ~]$ getsum -s 1 -e 100
Received parameters: getsum -s 1 -e 100
sum=5050