不要把測試用的執行檔名稱取成 "test" 。 test
是一個 shell
的內建指令。
參考資料:
/usr/share/doc/package
中的文件和範例
Unix / Programming
Information
從 GNU
可以獲得更多可印成紙本的豐富文件。
接下來的四個小節包含了用不同程式語言所寫的簡單 script
,其功能是建立一個文字檔,其內容可提供給像 newusers
之類的批次執行程式來使用,其功能是用來加入 /etc/passwd
的帳號資料。每個 script 都需要一個輸入檔,其每行都是像 first_name
last_name password 這樣的格式。 (這些 script 會建立實際的使用者 home
目錄。)
了解 Unix-like 系統如何工作的最好方法就是閱讀 shell
script。在此,我們對 shell 編程做個簡單的重點提示。從錯誤中學習,請參閱
Shell
Mistakes
。
Bash 的參考資料:
bash(1)
BASH Programming -
Introduction HOWTO
是初學者的資訊來源。
(安裝 bash-doc
套件可以看到更多的範例檔。)
簡短的程式範例 (從標準輸入讀取輸入,可提供 newusers
來建立帳號資訊) :
#!/bin/bash # (C) Osamu Aoki Sun Aug 26 16:53:55 UTC 2001 Public Domain pid=1000; while read n1 n2 n3 ; do if [ ${n1:0:1} != "#" ]; then let pid=$pid+1 echo ${n1}_${n2}:password:${pid}:${pid}:,,,/home/${n1}_${n2}:/bin/bash fi done
Debian 中有幾個套件提供了 POSIX shell :
dash
(Sarge)
ash
(Woody)
bash
pdksh
如果你想編寫具有可攜性的 shell script ,最好能寫成 POSIX shell script。可將
/bin/sh
鏈接到 ash
(或 dash
) 來測試和
POSIX 的相容性。最好能避免寫出包含 "bashisms" 或 "zshisms"
的 script 。例如,應避免下面的用法:
在這份文件中的敘述只適用於 POSIX 的 shell ,而不適用於 csh
式的
shell ,包括 tcsh
。
有幾個特別的參數是應該要記得的:
$0 = shell 的名稱或 shell script 的名稱 $1 = 第一個 shell 參數 ... $9 = 第九個 shell 參數 $# = 參數的個數 "$*" = "$1 $2 $3 $4 ... $n" "$@" = "$1" "$2" "$3" "$4" ... "$n" $? = 最近執行命令的退出狀態 $$ = 目前 shell script 的 PID $! = 最近啟動的背景執行工作的 PID
要記住的基本延伸參數:
從 如果 var 設定的話 如果 var 沒有設定的話 ${var:-string} $var string ${var:+string} string null ${var:=string} $var string (並且執行 var=string) ${var:?string} $var (echo string and then exit)
在這裡,這些操作中的冒號 `:' 都是選擇性的。
需要記住的基本參數代換:
從 結果 ${var%suffix} 移除最小符合 suffix 的後綴形式 ${var%%suffix} 移除最大符合 suffix 的後綴形式 ${var#prefix} 移除最小符合 prefix 的前綴形式 ${var##prefix} 移除最大符合 prefix 的前綴形式
需要記住的基本重導 (redirection)用法 (在此 [n] 是可指定的數字,代表檔案描述子 (file descriptor)):
[n]> file 將 stdout (或 n) 重導至 file 。 [n]>> file 將 stdout (或 n) 附加至 file 。 [n]< file 由 file 重導至 stdin (或 n)。 [n1]>&n2 將 stdout (或 n1) 重導至 n2 。 2> file >&2 將 stdout 和 stderr 重導至 file 。 > file 2>&1 將 stdout 和 stderr 重導至 file 。 | command 將 stdout 通過管線 (pipe) 傳遞給 command。 2>&1 | command 將 stdout 和 stderr 通過 pipe 傳遞給 command。
在這裡,
shell 允許你用其內建的 exec
,以任意的檔案描述子來開啟檔案。
$ echo Hello >foo $ exec 3<foo 4>bar # open files $ cat <&3 >&4 # redirect stdin to 3, stdout to 4 $ exec 3<&- 4>&- # close files $ cat bar Hello
在這裡的 n<&- 和 n>&- 是關閉檔案描述子 n 。
每個命令均可回傳一個退出狀態,而這個狀態值可用於條件判斷式:
注意此處的用法,回傳值 0
用來表示“真值,與計算機其它領域中常見的表示是不同的。另外 `[' 等同於使用
test
命令,並會將與 `]'
間的文字當成參數,所以相當於一個條件判斷式。
需要記住的基本條件式慣用法:
command && "如果前指令成功的話,也要執行這個指令" || true command || "如果前指令失敗的話,就執行這個指令" if [ 條件判斷式 ]; then "如果前指令成功的話,也要執行這個指令" else "如果前指令失敗的話,就執行這個指令" fi
在這裡的 || true 是需要的,以確保如果是用 -e 的選項在執行這行時,不會意外地結束程式。
在條件判斷式中的檔案比較有:
-e file 如果 file 存在則為真。 -d file 如果 file 存在且為一目錄則為真。 -f file 如果 file 存在且為一般檔案則為真。 -w file 如果 file 存在且可寫入則為真。 -x file 如果 file 存在且可執行則為真。 file1 -nt file2 如果 file1 比 file2 新的話則為真。 (modification) file1 -ot file2 如果 file1 比 file2 舊的話則為真。 (modification) file1 -ef file2 如果兩者的 device 和 inode 號碼都相同則為真。
在條件判斷式中的字串比較有:
-z str 如果 str 的長度是零則為真。 -n str 如果 str 的長度非零則為真。 str1 == str2 如果字串相等則為真。 str1 = str2 如果字串相等則為真。 (為了嚴格遵守和 POSIX 相容性,應用 "==" 來取代 "=") str1 != str2 如果字串不相等則為真。 str1 < str2 如果 str1 的排列順序在 str2 之前則為真 (和 locale 相關) 。 str1 > str2 如果 str1 的排列順序在 str2 之後則為真 (和 locale 相關) 。
在條件判斷式中的整數算術比較有 -eq 、 -ne 、 -lt 、 -le 、 -gt 和 -ge 。
Shell 會用下列的方法來處理 script :
在單引號中的雙引號是沒有作用的。
Executing set -x in the shell or invoking the shell with -x option make the shell to print all of commands executed. This is quite handy for debugging.
Awk 的參考資料:
mawk(1)
和 gawk(1)
簡短的程式範例 (從標準輸入讀取輸入,可提供 newusers
來建立帳號資訊) :
#!/usr/bin/awk -f # Script to create a file suitable for use in the 'newusers' command, # from a file consisting of user IDs and passwords in the form: # first_name last_name password # Copyright (c) KMSelf Sat Aug 25 20:47:38 PDT 2001 # Distributed under GNU GPL v 2, or at your option, any later version. # This program is distributed WITHOUT ANY WARRANTY. BEGIN { # Assign starting UID, GID if ( ARGC > 2 ) { startuid = ARGV[1] delete ARGV[1] } else { printf( "Usage: newusers startUID file\n" \ " where:\n" \ " startUID is the starting userid to add, and\n" \ " file is an input file in form:\n" \ " first_name last_name password\n" \ ) exit } infile = ARGV[1] printf( "Starting UID: %s\n\n", startuid ) } /^#/ { next } { ++record first = $1 last = $2 passwd = $3 user= substr( tolower( first ), 1, 1 ) tolower( last ) uid = startuid + record - 1 gid = uid printf( "%s:%s:%d:%d:%s %s,,/home/%s:/bin/bash\n", \ user, passwd, uid, gid, first, last, user \ ) }
在 Debian 中提供 POSIX awk
的套件:
mawk
gawk
這是 Unix-like 環境中最重要的直譯器。
Perl 的參考資料:
perl(1)
The Perl Directory
簡短的程式範例 (從標準輸入讀取輸入,可提供 newusers
來建立帳號資訊) :
#!/usr/bin/perl # (C) Osamu Aoki Sun Aug 26 16:53:55 UTC 2001 Public Domain $pid=1000; while (<STDIN>) { if (/^#/) { next;} chop; $pid++; ($n1, $n2, $n3) = split / /; print $n1,"_",$n2,":", $n3, ":",$pid, ":",$pid,",,,/home/",$n1,"_",$n2,":/bin/bash\n" }
安裝 Perl 模組 (model) module_name:
# perl -MCPAN -e 'install module_name'
這是一個不錯的物件導向直譯器
Python 的參考資料:
python(1)
Python Programming Language
簡短的程式範例 (從標準輸入讀取輸入,可提供 newusers
來建立帳號資訊) :
#! /usr/bin/env python import sys, string # (C) Osamu Aoki Sun Aug 26 16:53:55 UTC 2001 Public Domain # Ported from awk script by KMSelf Sat Aug 25 20:47:38 PDT 2001 # This program is distributed WITHOUT ANY WARRANTY. def usages(): print \ "Usage: ", sys.argv[0], " start_UID [filename]\n" \ "\tstartUID is the starting userid to add.\n" \ "\tfilename is input filename. If not specified, standard input.\n\n" \ "Input file format:\n"\ "\tfirst_name last_name password\n" return 1 def parsefile(startuid): # # main filtering # uid = startuid while 1: line = infile.readline() if not line: break if line[0] == '#': continue (first, last, passwd) = string.split(string.lower(line)) # above crashes with wrong # of parameters :-) user = first[0] + last gid = uid lineout = "%s:%s:%d:%d:%s %s,,/home/%s:/bin/bash\n" % \ (user, passwd, uid, gid, first, last, user) sys.stdout.write(lineout) +uid if __name__ == '__main__': if len(sys.argv) == 1: usages() else: uid = int(sys.argv[1]) #print "# UID start from: %d\n" % uid if len(sys.argv) > 1: infilename = string.join(sys.argv[2:]) infile = open(infilename, 'r') #print "# Read file from: %s\n\n" % infilename else: infile = sys.stdin parsefile(uid)
Make 的參考資料:
make(1)
簡單自動變數:
規則 (rule) 的語法:
target: [ prerequisites ... ] [TAB] command1 [TAB] -command2 # 忽略錯誤 [TAB] @command3 # 抑制 echo
這裡的 [TAB] 就是一個 TAB 。在 make
完成變數代換後,將會用 shell 逐行執行。在行尾使用 \ 可以續行。使用
$$ 可在 shell script 的環境中輸入 $ 。
適用於 target 和 prerequisites 的隱含規則 (Implicit rules),如下的例子:
%: %.c header.h
或,
%.o: %.c header.h
在此, target 包含了 % (exactly one of them), % 可匹配實際的目標檔名中任何的非空子串。 prerequisites 同樣也使用 % 來顯示它們的名稱是如何關聯到實際的目標檔名的。
後綴規則 (Suffix rules) 是用來定義 make
隱含規則的過時方法。GNU make
為了相容性的考量仍支持它,但只要可能的話就應該使用與之等價的規則:
舊的後綴規則 --> 新的規則 .c: --> % : %.c .c.o: --> %.o: %.c
規則中的自動變數:
foo.o: new1.c new2.c old1.c new3.c $@ == foo.o (目標) $< == new1.c (第一個) $? == new1.c new2.c new3.c (有更新的) $^ == new1.c new2.c old1.c new3.c (所有的) $* == 在 target 中 `%' 所匹配的文字。
變數參考:
foo1 := bar # 舊時的 expansion foo2 = bar # 遞迴的 expansion foo3 += bar # 附加 SRCS := $(wildcard *.c) OBJS := $(foo:c=o) OBJS := $(foo:%.c=%.o) OBJS := $(patsubst %.c,%.o,$(foo)) DIRS = $(dir directory/filename.ext) # 取出 "directory" $(notdir NAMES...), $(basename NAMES...), $(suffix NAMES...) ...
執行 make -p -f/dev/null 可查看內部自動規則。
準備工作:
# apt-get install glibc-doc manpages-dev libc6-dev gcc
C 的參考資料:
gcc(1)
each_C_library_function_name(3)
gcc
)
一個簡單的範例,將 example.c
和 libm
函式庫一起編譯,產生執行檔 run_example
:
$ cat > example.c << EOF #include <stdio.h> #include <math.h> #include <string.h> int main(int argc, char **argv, char **envp){ double x; char y[11]; x=sqrt(argc+7.5); strncpy(y, argv[0], 10); /* prevent buffer overflow */ y[10] = '\0'; /* fill to make sure string ends with '\0' */ printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]); return 0; } EOF $ gcc -Wall -g -o run_example example.c -lm $ ./run_example 1, 2.915, ./run_exam, (null) $ ./run_example 1234567890qwerty 2, 3.082, ./run_exam, 1234567890qwerty
在這裡,因為用到了 sqrt()
,所以必需要用
-lm 來連結 libm
函式庫。實際上的函式庫是位於 /lib/
中的 libm.so.6
,而這是個符號連結至 libm-2.1.3.so
。
請注意輸出文字的最後一個參數。即使已經指定了 %10s ,仍會超過 10 個字元。
不建議使用沒有邊界檢查的記憶體指標操作,如 sprintf
和
strcpy
。為預防暫存溢位的問題,請以 snprintf
和
strncpy
來取代。
gdb
來除錯準備工作:
# apt-get install gdb
gdb
參考資料:
gdb(1)
http://www.unknownroad.com/rtfm/gdbtut/gdbtoc.html
使用 gdb
的 -g
選項可以用來除錯已編譯的程式。很多命令都可以縮寫。 Tab expansion 的功能和在
shell 時一樣。
$ gdb program (gdb) b 1 # 在第一行設中斷點 (gdb) run arg1 arg2 arg3 # 執行程式 (gdb) next # 下一行 ... (gdb) step # 單步前進 ... (gdb) p parm # 印出 parm ... (gdb) p parm=12 # 設定其值為 12
在 Emacs 下做除錯的工作,請參閱 Editor 指令摘要 (Emacs , Vim), 第 11.3.4 節。
由於編譯好的軟體會被拆解成數個套件安裝到 Debian 系統,大部分的 debugging
symbols 是被移除的。為了讓 gdb
能有效地除錯 Debian
套件,相關的套件在重新編譯時需要注意下列項目:
debian/control
來分解套件 version
.
請參閱 Policy
10.1
了解更多資訊。
使用 ldd
可查看程式相依的函式庫:
$ ldd /bin/ls librt.so.1 => /lib/librt.so.1 (0x4001e000) libc.so.6 => /lib/libc.so.6 (0x40030000) libpthread.so.0 => /lib/libpthread.so.0 (0x40153000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
所以在 chroot
的環境下要使用 ls
,上列的函式庫在你的
chroot
的環境中都必需可用才行。
下面的命令也很有用:
strace
: 追蹤系統呼叫和訊息 (signal)
ltrace
: 追蹤函式庫呼叫
Debian 中有幾個記憶體漏失偵測工具。
njamd
valgrind
dmalloc
electric-fence
memprof
memwatch
(沒有包成套件,可在 memwatch
取得。)
mpatrol
leaktracer
libgc6
Parasoft
。
(非自由軟體,商業用途要付費)
也可參閱 Debugging
Tools for Dynamic Storage Allocation and Memory Management
。
flex
是一個快速的字詞分析產生器。
flex
的參考資料:
flex(1)
需要提供你自己的 main()
和 yywrap()
,或者你的
program.l
在不用 library 時應該看起來看像這樣
(yywrap
是一個巨集;%option main 隱含地打開了
%option noyywrap):
%option main %% .|\n ECHO ; %%
另外,還可以在 cc
命令列末尾加上 -lfl
連接器的選項來進行編譯 (就像 AT&T-Lex 使用 -ll
一樣),此時就不需要 %option 了。
Debian 中有幾個套件提供了與 Yacc 兼容的 LALR 文法分析生成器:
bison
: GNU LALR 文法分析產生器
byacc
: The Berkeley LALR 文法分析產生器
byyacc
: Backtracking parser generator ,以 byacc
為基礎
bison
的參考資料:
bison(1)
需要提供自己的 main()
和 yyerror()
。
main()
呼叫 yyparse()
,而 yyparse()
呼叫 yylex()
,通常由 FleX 建立。
%% %%
autoconf
一個 shell script 生成工具,由它生成的 script
能自動設定軟體的源碼套件,以適用於各種使用完整 GNU build 系統的 UNIX-like
系統。
autoconf
會產生設定 script 的 configure
。
configure
使用 Makefile.in
模版來自動建立適合的
Makefile
。
Debian 不會改動 /usr/local
下的文件 (參閱 多樣性支援, 第 2.5
節)。所以如果是從源碼來編譯程式,並將其安裝到 /usr/local
下,就不會影響到 Debian。
$ cd src $ ./configure --prefix=/usr/local $ make $ make install # 這會把檔案放到系統中
如果你仍保有源碼,而且是用 autoconf
/automake
,你也記得是如何進行設定的話:
$ ./configure all-of-the-options-you-gave-it # make uninstall
另一種方法是,如果可以確定安裝過程將檔案都放在 /usr/local/
,並且該目錄下沒有什麼別的重要文件的話,可用下面的命令將其全部刪除:
# find /usr/local -type f -print0 | xargs -0 rm -f
如果不能確定文件安裝到什麼位置,最好使用 checkinstall
,可提供明確用來反安裝的路徑。
基本的交談性動態網頁可以利用下列方式來實現:
program.*
)
會收到解碼後的參數 "VAR1=VAL1 VAR2=VAL2 VAR3=VAL3"
來當成環境變數 "QUERY_STRING" 並執行。
為了安全性的考量,最好能避免手動分析這些 CGI 參數。有一些 Perl(參閱Perl, 第 13.4 節)和 Python(參閱Python,
第 13.5 節)能達成這些功能。PHP
已經內建這些函式。如果需要儲存 client
端的資料,請使用 cookies。處理 client 端的資料,通常是使用 javascript。
更多的資訊請閱讀 The Common
Gateway Interface
, The Apache
Software Foundation
, 和 JavaScript
。
在瀏覽器上利用已編碼的網址 http://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial 在 Google 上查詢 "CGI tutorial" 來查閱 CGI script 對於伺服器的處理是不錯的辦法喔。
傳統上, roff 是主要的 Unix 文字處理系統。
參閱 roff(7)
, groff(7)
, groff(1)
,
grotty(1)
, troff(1)
, groff_mdoc(7)
, groff_man(7)
, groff_ms(7)
,
groff_me(7)
, groff_mm(7)
和 info groff
。
在 -me
巨集中有份不錯的教程。如果你是用 groff
(1.18
以上版本),找到 /usr/share/doc/groff/meintro.me.gz
並做下面的動作:
$ zcat /usr/share/doc/groff/meintro.me.gz | \ groff -Tascii -me - | less -R
下面的作法將產生一份完整的純文字檔案:
$ zcat /usr/share/doc/groff/meintro.me.gz | \ GROFF_NO_SGR=1 groff -Tascii -me - | col -b -x > meintro.txt
如果要列印的話,就用 PostScript 輸出。
$ groff -Tps meintro.txt | lpr $ groff -Tps meintro.txt | mpage -2 | lpr
準備工作:
# apt-get install debiandoc-sgml debiandoc-sgml-doc
debiandoc-sgml
的參考資料:
/usr/share/doc/debiandoc-sgml-doc
debiandoc-sgml(1)
DocBook:
The Definitive Guide
, by Walsh and Muellner, (O'Reilly)
(package docbook-defguide
)
SGML 能夠管理一份文件的多種格式。 Debiandoc 是個較簡單的 SGML 系統,本文件就是用它來編寫。只需將原本的文字檔對下列字元進行少許轉換:
要把一段文字變成不輸出的註解的話,請輸入:
<!-- State issue here ... -->
要把一段文字變成可選擇是否輸出的註解的話,請輸入:
<![ %FIXME; [ State issue here ... ]]>
在 SGML 中,只有首次定義 (first definition)是有效的。例如:
<!entity % qref "INCLUDE"> <![ %qref; [ <!entity param "Data 1"> ]]> <!entity param "Data 2"> ¶m;
最後結果是 "Data 1" 。如果第一行是用 "IGNORE" 而不是 "INCLUDE" ,則結果是 "Data 2" (第二行是條件判斷式) 。而且,重覆出現的文字可提前在文件中定義。
<!entity whoisthis "my"> Hello &whoisthis; friend. This is &whoisthis; book.
結果如下:
Hello my friend. This is my book.
可參閱 examples
目錄中簡短的 SGML 範例文件
sample.sgml
。
當 SGML 文件不斷增大後,有時以 Tex 做為後端文字處理會出現問題,請參閱 TeX/LaTeX, 第 13.9.3 節 。
事前準備:
# tasksel # 請選擇 Miscellaneous --> TeX/LaTeX environment
LaTeX 的參考手冊:
The teTeX HOWTO: The
Linux-teTeX Local Guide
tex(1)
latex(1)
TeX 是一個強大的寫作環境。許多 SGML
處理程式使用它來當作後端文字處理器。lyx
、lyx-xforms
或lyx-qt
內附的
Lyx 以及 GNU TeXmacs 內附的texmacs
提供了相當不錯的 WYSIWYG
編輯環境。 使用者大多採用 Emacs 和 Vim 當作撰寫 LaTeX 原始碼的編輯器。
下列有許多線上參考資料:
teTeX - A Documentation
Guide
(tetex-doc
package)
A Quick Introduction
to LaTeX
A Simple
Guide to Latex/Lyx
Word
Processing Using LaTeX
Local
User Guide to teTeX/LaTeX
當文件越來越大時,編譯 TeX
有時候會出錯。使用者必須編輯/etc/texmf/texmf.cnf
(或者適當地修改
/etc/texmf/texmf.d/95NonPath
並執行update-texmf
)加大
pool size 來修正該問題。
和在編程時寫文件不同的,文學編程者是在寫文件時編程。這個方法確保程式有個良好的文件。
要對文學編程有更多了解,請參閱 Literate Programming
。
準備工作:
# apt-get install nowebm
Noweb 的參考資料:
這是個 WEB-like 的文學編程工具,可更容易地提供擴充性和與語言無關性, [71] When noweb
is
invoked, it writes the program source code to the output files mentioned in the
noweb file, and it writes a TeX file for typeset documentation.
Debian 中的 ifupdown
套件是個好例子。
$ apt-get source ifupdown $ cd ifupdown* $ make ifupdown.pdf ifupdown.ps
準備工作:
# apt-get install doxygen doxygen-doc doxygen-gui
Doxygen 的參考資料 (也是用 doxygen
建立的!):
它可以由 C++ 、 C 、 Java 、 IDL 和一些 PHP 和 C# 程式產生 HTML 、 RTF 、 Unix
manual pages 、 PostScript 和 PDF (使用 LaTeX) 文件。Doxygen 相容於 JavaDoc
(1.1) 、 Qt-Doc 、 KDOC 並被特別設計為用在使用到 Troll Tech's Qt
toolkit 的專案中。它可以建立
include 相依圖,
合作圖表,和圖型化的類別繼承圖,即使在沒有被文件化的程式。它的輸出是類似 Qt
的文件。
準備工作:
# apt-get install debian-policy developers-reference \ maint-guide dh-make debhelper # apt-get install packaging-manual # 如果是 Potato
包裝套件的參考資料:
dh-make(1)
Joey Hess 的單一二進位套件快速粗糙的打包法:
# mkdir -p mypkg/usr/bin mypkg/DEBIAN # cp binary mypkg/usr/bin # cat > mypkg/DEBIAN/control Package: mypackage Version: 1 Architecture: i386 Maintainer: Joey Hess <joeyh@debian.org> Description: my little package Don't expect much. ^D # dpkg-deb -b mypkg
使用 dh-make
套件中的 dh_make
來建立一個基本的套件。接著按照 dh-make(1)
中描述的方法進行。會用到
debian/rules
中的 debhelper
。
一個較舊的方法是使用 debmake
套件中的 deb-make
。不需要 debhelper
script,只需要 shell 就行了。
有關多重源碼套件 (multiple-source) 的例子,參閱 "mc"
(dpkg-source -x mc_4.5.54.dsc) ,其中用到 Adam Heath(doogie@debian.org
) 的
"sys-build.mk" 以及 "glibc" (dpkg-source -x
glibc_2.2.4-1.dsc) ,它使用到已故的 Joel Klecker(espy@debian.org
) 所寫的另一個系統。
Debian 參考手冊
CVS, 週一 四月 3 22:58:37 UTC 2005osamu@debian.org
asho@debian.org.tw