UNIX環境進階編程看了三章,遇到不少重新導向等shell命令。本想到Linux時再講,看來有必要提前了。之前有看過一本《嵌入式Linux軟硬體開發詳解》這本書裡有簡單介紹了一部分shell常用命令,就結合它來簡單介紹下shell編程。畢竟沒有詳細看過shell相關的書籍,等以後看過了再詳細講吧。
首先,推薦一款 shell 線上工具
擴充學習:Shell 教程
相關書籍:Linux命令列與Shell指令碼編程大全
常用快速鍵:
Ctrl+C強制終止當前命令 Ctrl+L 清屏,相當於clear Ctrl+U 刪除或者剪下游標之前的所有命令,比退格方式更快捷 Ctrl+K 刪除或者剪下游標之後的所有命令 Ctrl+Y 粘貼Ctrl+U或者Ctrl+K剪下的內容 Ctrl+R 實現搜尋曆史命令,先輸入Ctrl+R,然後斷行符號再輸入需要搜尋的曆史命令 Ctrl+D 退出當前終端 Ctrl+Z 暫停命令並且放入後台,不能經常使用 Ctrl+S 暫停螢幕輸出 Ctrl+Q 恢複螢幕輸出
一、bash shell 簡介 1、在UNIX基礎知識這章中,有簡單介紹shell: shell 是一個命令列解譯器,它讀取使用者輸入,然後執行命令。shell 使用者輸入通常來自終端(互動式 shell),有時則來自於檔案(稱為 shell 指令碼)。
UNIX系統中常見的 shell: Bourne shell 路徑:/bin/sh
Bourne-again shell 路徑:/bin/bash
C shell 路徑:/bin/csh
Korn shell 路徑:/bin/ksh
TENEX C shell 路徑:/bin/tcsh
其中的 Bourne-again shell 就是我們要講的簡稱 bash shell,它是 GNU shell,所有 Linux 系統都是提供這種 shell 。它的設計遵循 POSIX 標準,同時保留了與 Bourne shell 的相容性。它支援 C shell 和 Korn shell 兩者的特色。 系統從口令檔案中相應的使用者登入項的最後一個欄位中瞭解到應該為該登入使用者執行哪一個 shell。 我用的虛擬機器是 Ubuntu 12.04,核心是 Linux 3.2.0,使用 root 超級使用者。查看使用者登入檔案 /etc/passwd
查看 /etc/passwd :root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/bin/shbin:x:2:2:bin:/bin:/bin/shsys:x:3:3:sys:/dev:/bin/shsync:x:4:65534:sync:/bin:/bin/syncgames:x:5:60:games:/usr/games:/bin/shman:x:6:12:man:/var/cache/man:/bin/sh
可以看到:root:x:0:0:root:/root:/bin/bash 所以,我所執行的是
bash shell 其他欄位含義,可
參看:UNIX再學習 -- 再識
2、與其他 shell 比較 bash shell 是 Linux 作業系統中標準的 shell,當前幾乎所有 Linux 版本都使用 bash shell 作為系統管理的核心,相比其他 shell ,bash shell 具有更加強大的功能:
(1)命令記憶功能 我們通過按鍵盤上的 【上下鍵】 可以查看到之前使用過的指令。每次登陸後執行的指令都被暫存在緩衝區中,成功退出系統後,該指令便會記錄到 bash_history 檔案當中。通過這一功能,我們可以很方便地修改錯誤的執行命令。
(2)命令與檔案補全功能 使用此功能,我們可以少打很多字並且確保輸入的資料是正確的。【Tab】 接在一串命令的第一個字的後面,為“命令補全”;【Tab】接在一串命令的第二個字的後面,則為“檔案補全”。通過這一功能,我們可以快速查看或匹配目前的目錄下相關命令或檔案。
(3)命令別名設定功能 Linux 系統中包含有千差萬別的命令名及參數,既不方便使用也不方便管理。bash shell 中提供了利用 Alias 自訂命令
別名的功能。
(4)編程功能 shell 不僅可以作為命令直譯器用來定製工作環境,還可以作為一門進階程式設計語言編寫執行使用者指令的
指令碼,從而更加快速有效地處理複雜的任務。
二、bash shell 常用命令 當
使用者登入到 Linux 系統時,便開始於 bash 進行互動,一直到使用者登出為止(以後講 Linux啟動時會詳細介紹這部分)。如果是普通使用者,則 bash 的
預設提示符為“$”(代表普通使用者),如果是
root 超級使用者,提示符則變為“#”。使用者與系統互動的過程便是通過在提示符後面輸入操作命令來完成的。 為了加強 shell 的處理能力,bash shell 除本身內建一部分命令,如 cd 等,還增加了對外部應用程式命令的支援,如 ls、ps等。 在 shell 的命令提示字元後面輸入的命令,如果是 bash shell 內建的命令,則有它自己負責回應;如果是外部應用程式命令,則 shell 會找出對應的外部應用程式,然後將控制權交給核心,由核心執行該應用程式之後再講控制權交回給 shell。
常見命令如下: 這部分更多內容,
搜尋:Linux命令大全 Shell內建命令
1、type
命令格式:type 參數命令
功能:判斷一個命令是內建命令還是外部命令
選項:
-t:輸出“file”、“alias”或者“builtin”,分別表示給定的指令為“外部指令”、“命令別名”或者“內部指令”;-p:如果給出的指令為外部指令,則顯示其絕對路徑; -a:在環境變數“PATH”指定的路徑中,顯示給定指令的資訊,包括命令別名。
執行個體:
# type lsls 是 `ls --color=auto' 的別名# type -t lsalias# type -a lsls 是 `ls --color=auto' 的別名ls 是 /bin/ls可以看出,ls為命令別名
# type cdcd 是 shell 內嵌# type -t cdbuiltin# type -a cdcd 是 shell 內嵌可以看出,cd為內部命令
# type whichwhich 是 /usr/bin/which# type -t whichfile# type -p which/usr/bin/which# type -a whichwhich 是 /usr/bin/whichwhich 是 /bin/which可以看出,which為外部命令
通過,type 命令的用法,我們可以知道每個命令是否為 bash 內建命令。此外,使用 type 搜尋後面的名稱時,如果後接的名稱不能以執行檔案的狀態找到,那麼該名稱不會顯示。
2、echo
命令格式:echo arg
功能:在螢幕上顯示出有 arg 指定的字串
執行個體:
簡單顯示:# echo hellohello
建立shell指令碼:gedit hello.sh#!/bin/bashecho "hello world!"執行 ./hello.shbash: ./hello.sh: 許可權不夠添加許可權:chmod +x *.sh 或者 chmod 777 *.sh# ./hello.sh hello world!
擴充部分:echo命令
選項:
-e:啟用逸出字元。
使用-e選項時,若字串中出現以下字元,則特別加以處理,而不會將它當成一般文字輸出:
\a 發出警告聲; \b 刪除前一個字元; \c 最後不加上分行符號號; \f 換行但游標仍舊停留在原來的位置; \n 換行且游標移至行首; \r 游標移至行首,但不換行;\t 插入tab; \v 與\f相同; \\ 插入\字元; \nnn 插入nnn(八進位)所代表的ASCII字元;
執行個體:
# echo -e "\e[1;31mThis is red text\e[0m"This is red text# echo -e "\e[1;42mGreed Background\e[0m"Greed Background
3、export 這部分再講環境變數時講過了,
參看:UNIX再學習 -- 環境變數
命令格式1:export variable
功能:shell 可以用 export 把它的變數向下帶入 子 shell,從而讓子進程繼承父進程中的環境變數。但子 shell 不能用 export 把它的變數向上帶入父進程。
執行個體:
# export HELLO="hello" # echo $HELLO hello
命令格式2:export
功能:顯示當前所有環境變數及其內容。
執行個體:
# exportdeclare -x COLORTERM="gnome-terminal"declare -x DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-Kss6b0aquA,guid=297ad74aed4e17b7f89f981d0000003c"declare -x DEFAULTS_PATH="/usr/share/gconf/ubuntu-2d.default.path"declare -x DESKTOP_SESSION="ubuntu-2d"declare -x DISPLAY=":0"declare -x GDMSESSION="ubuntu-2d"declare -x GNOME_DESKTOP_SESSION_ID="this-is-deprecated"declare -x GNOME_KEYRING_CONTROL="/tmp/keyring-qyAxFa"declare -x GPG_AGENT_INFO="/tmp/keyring-qyAxFa/gpg:0:1"declare -x GTK_IM_MODULE="ibus"declare -x HOME="/root".....
4、readonly
命令格式1:readonly variable 功能:將一個使用者自訂的 shell 變數標識為不可變
執行個體:
# export HELLO="hello" # readonly HELLO="hello" # export HELLO="hello" world bash: HELLO: 唯讀變數 # unset HELLO bash: unset: HELLO: 無法反設定: 唯讀 variable
命令格式2:readonly
功能:顯示出所有唯讀 shell 變數
執行個體:
# readonlydeclare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath"declare -ir BASHPIDdeclare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="24" [3]="1" [4]="release" [5]="i686-pc-linux-gnu")'declare -ir EUID="0"declare -ir PPID="2590"declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"declare -ir UID="0"
5、read
命令格式:read variable
功能:從標準輸入裝置讀入一行,分解成若干行,賦值給 shell 程式定義的變數。
執行個體:
建立shell指令碼:gedit hello.sh#!/bin/bashecho -e "Please enter: \c"read xecho "you enter: $x"執行指令碼:# ./hello.sh Please enter: hello world!you enter: hello world!
再例如,終端輸入密碼時候,不讓密碼顯示出來,可建立如下指令碼:
方法一:建立指令碼:#!/bin/bash read -p "輸入密碼:" -s pwd echo echo password read, is "$pwd"執行指令碼:./hello.sh輸入密碼:password read, is 12345
方法二:建立指令碼:#!/bin/bash stty -echoread -p "輸入密碼:" pwdstty echoechoecho 輸入完畢執行指令碼:./hello.sh輸入密碼:輸入完畢
注意: stty -echo 選項 -echo 禁止將輸出發送到終端,而選項 echo 則允許發送輸出。
6、env
命令格式:env
功能:顯示環境變數及其內容。
執行個體:
# envLC_PAPER=en_US.UTF-8LC_ADDRESS=en_US.UTF-8SSH_AGENT_PID=1749LC_MONETARY=en_US.UTF-8GPG_AGENT_INFO=/tmp/keyring-qyAxFa/gpg:0:1TERM=xtermSHELL=/bin/bash.....
7、set
命令格式:set
功能:顯示所有變數及其內容
執行個體:
# setBASH=/bin/bashBASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:progcomp:promptvars:sourcepathBASH_ALIASES=()BASH_ARGC=()BASH_ARGV=()BASH_CMDS=()BASH_LINENO=()BASH_SOURCE=().....
8、unset
命令格式:unset
功能:從環境中刪除變數或函數。這個命令不能刪除 shell 本身定義的唯讀變數。
執行個體:
# export HELLO="hello" # unset HELLO # echo $HELLO #
9、grep
命令格式:grep 參數 string 目標檔案
功能:在指定檔案一堆檔案中尋找一個特定的字串並將字串所在行輸出到終端或平台。
參看:grep 命令
選項:
-a 不要忽略位元據。 -A<顯示列數> 除了顯示符合範本樣式的那一行之外,並顯示該行之後的內容。 -b 在顯示符合範本樣式的那一行之外,並顯示該行之前的內容。 -c 計算符合範本樣式的列數。 -C<顯示列數>或-<顯示列數> 除了顯示符合範本樣式的那一列之外,並顯示該列之前後的內容。 -d<進行動作> 當指定要尋找的是目錄而非檔案時,必須使用這項參數,否則grep命令將回報資訊並停止動作。 -e<範本樣式> 指定字串作為尋找檔案內容的範本樣式。 -E 將範本樣式為延伸的普通標記法來使用,意味著使用能使用擴充Regex。 -f<範本檔案> 指定範本檔案,其內容有一個或多個範本樣式,讓grep尋找符合範本條件的檔案內容,格式為每一列的範本樣式。 -F 將範本樣式視為固定字串的列表。 -G 將範本樣式視為普通的標記法來使用。 -h 在顯示符合範本樣式的那一列之前,不標示該列所屬的檔案名稱。 -H 在顯示符合範本樣式的那一列之前,標示該列的檔案名稱。 -i 胡列字元大小寫差別。 -l 列出檔案內容符合指定的範本樣式的檔案名稱。 -L 列出檔案內容不符合指定的範本樣式的檔案名稱。 -n 在顯示符合範本樣式的那一列之前,標示出該列的編號。 -q 不顯示任何資訊。 -R/-r 此參數的效果和指定“-d recurse”參數相同。 -s 不顯示錯誤資訊。 -v 反轉尋找。 -w 只顯示全字元合的列。 -x 只顯示全列符合的列。 -y 此參數效果跟“-i”相同。 -o 只輸出檔案中匹配到的部分。
常用方法:
當前所有含 hello 的檔案# grep "hello" * -Rn 當前所有不含 hello 的檔案 # grep "hello" * -vn
10、wc
命令格式:wc 參數檔案1 檔案2 ....
功能:統計指定檔案中的位元組數、字數、行數並將統計結果顯示輸出。
選項:
-c或--bytes或——chars:只顯示Bytes數; -l或——lines:只顯示列數; -w或——words:只顯示字數。
執行個體:
# wc aio.h 246 967 7502 aio.h分別是: 列數 字數 位元組數 檔案名稱
三、重新導向與管道 shell 命令在執行時,會自動開啟三個標準檔案,標準輸入檔案(stdin,一般對應終端的鍵盤),標準輸出檔案(stdout)和標準出錯輸出檔案(stderr,對應終端的螢幕),
參看:C語言再學習 -- 檔案 在實際應用中,這三個檔案常常需要按照新的格式進行定向,
從其他檔案中匯入內容或將內容匯出到其他檔案中,這個過程就是
重新導向;
使內容按照一定格式輸出,這就是
管道。
1、重新導向
重新導向可分為輸出重新導向、錯誤重新導向與輸入重新導向
(1)輸出重新導向 通過
重新導向符“>”或“>>”將命令的標準輸出重新定向到指定檔案中。
一般形式:命令 > 檔案名稱 “>”與“>>”都能將內容重新寫入到檔案中,但如果檔案中有內容,執行“>”後新的內容將會覆蓋掉原來的內容,而“>>”則是將新的輸出內容附加到原來內容的結尾。
執行個體:
建立text.txt# touch text.txt將ps內容輸出到 text.txt 檔案中# ps > text.txt 查看 text.txt 內容# cat text.txt PID TTY TIME CMD 2600 pts/0 00:00:00 bash 3231 pts/0 00:00:00 ps如果再將 ls內容使用 ">" 輸出到 text.txt 檔案中# ls > text.txt 再查看 text.txt內容,則覆蓋掉了原來的內容# cat text.txt text.txt如果再將 ps內容使用 ">>" 輸出到 text.txt 檔案中# ps >> text.txt 再查看 text.txt內容,則附加到原來的內容的結尾# cat text.txt text.txt PID TTY TIME CMD 2600 pts/0 00:00:00 bash 3236 pts/0 00:00:00 ps
(2)錯誤重新導向 通過
重新導向符“2>”或“2>>”將命令的標準錯誤輸出重新導向到指定檔案中。 “2>”和 “2>>”區別同上面的“>”和“>>”這裡就不做說明了。
一般形式: 命令 2> 檔案名稱 命令 2>> 檔案名稱
執行個體:
hello沒有這個檔案,查看會出錯# cat hellocat: hello: 沒有那個檔案或目錄將錯誤儲存到 text.txt 檔案中# cat hello 2> text.txt # cat text.txt cat: hello: 沒有那個檔案或目錄
(3)輸入重新導向 通過
重新導向符“<”將命令的標準輸入重新置放到指定檔案中。
一般形式:命令 < 檔案名稱
執行個體:
查看指令碼# cat sh.sh echo “you working directory is $(pwd)”echo "the time is $(date)"shell命令解析程式從指令碼程式 sh.sh 中讀取命令列並加以執行# bash < sh.sh “you working directory is /home/tarena/project/c_test”the time is Wed Mar 22 10:07:45 CST 2017
2、管道 在 Linux 下我們可以採用管道操作符 “|”來串連多個命令或進程,在串連的管道線兩邊,每個命令執行時都是一個獨立的進程。前一個命令的輸出正是下一個命令的輸入。這些進程可以同時進行,而且隨著資料流在它們之間的傳遞可以自動地進行協調,從而能夠完成較為複雜的任務。管道我們也並不陌生,之前講 xargs 用法時有用到的。
參看:C語言再學習 -- Xargs用法詳解
一般形式:[命令1] | [命令2] | [命令3]
執行個體:
ls 命令查看# lssh.sh text.txt可以可以指定尋找指令檔# ls | grep *shsh.sh
四、shell簡單應用 shell 除了作為命令編譯器用於管理命令外,還可以
用來進行程式設計。它提供了定義變數和參數的手段以及豐富的過程式控制制結構。使用 shell 編程類似於使用 DOS 中的批次檔,稱為
shell 指令碼,又叫 shell 程式 或 shell 命令檔案。
1、基本用法
(1)開頭 程式必須以下面的行開始,且必須放在檔案的第一行。
#。/bin/bash
符號“#!”用來
告訴系統它後面的參數是用來執行該檔案的程式,在這個例子中使用
/bin/bash 來執行程式。 而 /bin/bash 正是 bash shell 的路徑。 當編譯好指令碼時,如果要執行該指令碼,我們還必須使其可執行。要使指令碼可執行,我們需賦予該檔案可執行檔許可權,可以使用如下命令檔案:
chmod +x [檔案] 或者 chmod 777 [檔案]
修改檔案許可權,之前也有講可
參看:C語言再學習 -- 修改linux檔案許可權
(2)注釋 在進行 shell 編程時,
以“#”開頭的句子表示注釋,直到這一行的結束,我們建議在程式中使用注釋。使用注釋,即使相當長的時間內沒有使用該指令碼,我們也能在很短的時間內明白該指令碼的作用及工作原理。
(3)提示符 在指令碼中使用
提示符“$”,後面使用圓括弧括住命令,則可以執行該命令。 如果是
環境變數,則直接跟在“$”後面。
執行個體:
查看指令碼# cat sh.sh #!/bin/bashecho $(ls)echo $SHELL執行指令碼# ./sh.sh sh.sh text.txt/bin/bash
2、指令碼示範
(1)建立指令碼
#!/bin/bash#program date#show the date in this wayecho "Mr.$USER,Today is:"#echo $(date)echo $(date)echo Wish you a lucky day !
(2)設定可執行許可權
# chmod 777 sh.sh
(3)執行程式