前言
命令列參數的目的在改變命令列工具的行為,以符合當下的需求。本文說明如何在 shell script 中處理命令列參數。
命令列參數的資料結構
命令列參數是以空白隔開的串列。在 shell script 中以特殊變數 $@
來代表。
這裡使用 for
迴圈逐一走訪命令列參數:
#!/bin/sh
for param in $@;
do
echo $param;
done
exit 0;
輸入五個參數時,正確地將參數逐一印出:
$ ./params a b c d e
a
b
c
d
e
但參數中有空白符時,會錯誤地將該參數拆開:
$ ./params "a and b" c d e
a
and
b
c
d
e
這不是預期中的結果,"a and b"
錯誤地拆成三個參數。
應對的方式是用一對雙引號 "
把特殊變數 $@
包起來:
#!/bin/sh
for param in "$@";
do
echo $param;
done
exit 0;
這時候命令列參數會正確地拆開:
$ ./params "a and b" c d e
a and b
c
d
e
另外一種方式是改用 while
迴圈來走訪參數。根據參數數量 $#
來決定迴圈的終止條件,每次迭代用 shift
取出一個參數:
#!/bin/sh
while [ $# -gt 0 ];
do
echo $1;
shift;
done
exit 0;
這時也可正確地拆解參數:
$ ./params "a and b" c d e
a and b
c
d
e
自行解析命令列參數
先前的例子僅是展示參數的資料結構,但未處理參數。本節展示一個處理參數的虛擬程式:
#!/bin/sh
program=$0;
version="0.1.0";
while [ $# -gt 0 ];
do
_param=$1;
case $_param in
"-v"|"--version")
echo $version;
exit 0;
;;
"-h"|"--help")
echo "Usage: $program path/to/file ...";
exit 0;
;;
-*)
echo "Unknown parameter: $_param" >&2;
exit 1;
;;
*)
break;
;;
esac
done
while [ $# -gt 0 ];
do
echo $1;
shift;
done
exit 0;
這個程式使用兩個 while
迴圈。第一個 while
迴圈處理選擇性參數,並對各個參數執行相對應的動作。第二個 while
迴圈則逐一走訪完剩下的參數。
本範例程式未使用其他工具,以純手動的方式解柝命令列參數。
傳遞命令列參數給另一個程式
有時候,命令列工具會呼叫另一個命令列工具。這時要如何區分參數是傳給那個命令列程式呢?約定俗成的方式是以 --
做為命令列參數的分隔符。在 --
前的參數會傳給原程式,在其後的參數則會傳給目標程式。
ccrun 是 shell 寫成的小工具,其功能為快速地編譯和執行 C 和 C++ 程式碼,不需要寫 Makefile。對於小型的練習程式碼來說相當方便。
執行 ccrun
的虛擬指令如下:
$ ccrun path/to/*.c -- --version
在 --
後的參數 --version
不是傳給 ccrun
本身,而是傳給自動編譯出來的命令列程式。
這裡節錄出 ccrun
一部分的程式碼:
# Excerpt.
args="";
is_arg=0;
for arg in $@;
do
if [ "$arg" = "--" ];
then
is_arg=1;
continue;
fi
if [ $is_arg -eq 1 ];
then
args="$args $arg";
fi
done
if ! LD_LIBRARY_PATH=$LD_LIBRARY_PATH ./$dest $args;
then
clean;
exit 1;
fi
由此可看出,在 ccrun
偵測到 --
時,開啟旗標 is_arg
,並收集後續的參數。然後將收集到的參數丟給目標程式來執行。