Linux Bash Shell學習(八):shell程式設計基礎——string操作

愷風發表於2009-12-21

  本文也即《Learning the bash Shell》3rd Edition的第四章Basic Shell Programming之讀書筆記之二,但我們將不限於此。

String操作

  在下面的描述中,“:”是可以刪除的,存在是表示“存在但不允許為null”,不帶“:”表示“存在”,即允許為空:

${ varname :- word } :如果varname存在並且不為null,返回varname的值,否則返回word。用於當某個變數不存在或沒定義時返回一個預設的值。如果為${ varname - word } ,則當varname存在,可以為null,例如我們定義myparam=,返回varname的值,否則返回word。下面也可以刪除“:”,含義相同,不在複述。

${ varname := word } :如果varname存在並且不為null,返回varname的值,否則向其賦值為word,並返回該值。用於對某個不存在或沒定義變數設定預設。對於位置引數是隻讀不能賦值。

${ varname :? message } :如果varname存在並且不為null,返回varname的值,否則列印資訊varname:message,並abort指令碼,如果我們沒有設定message,將使用預設的“parameter null or not set”。用於檢查變數沒有定義的錯誤。

${ varname :+ word } :如果varname存在並且不為null,返回word的值,否則返回null。用於檢測變數是否存在。

${ varname : offset : length } :獲取substring的操作。他返回從varname中從offset位置開始,長度為length的字串。第一個位置為0,如果不給出length或者無效(小於0),則返回offset之後全部的字元,如果是{@:offset:length},則返回指令碼引數從第offset個引數開始的總共length個引數。

  下面給出一個例子來學習他們的用法。我們建立一個檔案,在裡面存貯一些條目,我們希望能對條目進行排序,從大到小,並輸出最前的N個條目。檔案例如子如下:

[wei@wei-desktop bash-learning]$ cat myinfo
5    Depeche Mode
2    Split Enz
3    Simple Minds
1    Vivaldi, Antonio
20  Hello, world
7    adsf,dafdsf
15  Hello, myfriend

  我們建立我們的指令碼檔案highest用作測試,內容如下:其他顏色字型表示說明,不作為檔案的一部分,我們用註釋的方式,也不影響檔案的執行

# ”#“開始表示註釋行,一個良好的變成習慣是檔案的開始給出檔案的資訊,以便閱讀
# highest [howmany]
# sort the entry inf on a descend order, and high line the top
# [hwomany] entry, default is 5
#
# 要求使用者給出引數<檔名>,否則退出指令碼,要求使用者給出顯示的條目,否則使用預設值5
filename=${1? 'Used command ./test [entry_num]'}
howmany=${2:-5}
# header是用來表明輸出的時候顯示的某些資訊,如果這行我們註釋掉,將不顯示
header=set
#echo帶有兩個引數-n,表示顯示後不執行LINEFEED,即不換行。-e表示解析/n,不將其作為兩個字元,視為換行符號。我們如果註釋掉header,則不會顯示任何內容。
echo -e -n ${header:+"num    name/n"}
echo -e -n ${header:+"----    -----/n"}
#sort是個排序的命令,-r表示reverse的順序,即從大到小,-n表示將第一個引數視為數字,而不是character的方式。| 表示pipe輸出,head -N 表示顯示頭N行。
sort -nr $filename | head -$howmany

樣式匹配

  Pattern可以包含wildcard,操作如下:

  • ${variable #pattern } :如果變數的開始匹配pattern,則去除最小匹配,返回後面的字元,如果不匹配,給出變數。
  • ${variable ##pattern } :如果變數的開始匹配pattern,則去除最大匹配,返回後面的字元,如果不匹配,給出變數。
  • ${variable %pattern } :如果變數的最後匹配pattern,則去除最 匹配,返回前面的字元,如果不匹配,給出變數。
  • ${variable %%pattern } :如果變數的最後匹配pattern,則去除最大匹配,返回 面的字元,如果不匹配,給出變數。
  • ${variable /pattern/string } :將第一個匹配更換為string,如果string為null,則刪除。如果variable是@或者*,則根據命令所得的引數為單元來執行。
  • ${variable //pattern/string } :將所有匹配更換為string,如果string為null,則刪除。如果variable是@或者*,則根據命令所得的引數為單元來執行。

  最大或者最小批評只有在含有萬用字元的情況下有區別,否是對於精確匹配都是無區別的。下面是例子。

[wei@wei-desktop bash-learning]$ echo $aa
abc.xyz.hello.world
[wei@wei-desktop bash-learning]$ echo ${aa#*.}
xyz.hello.world
[wei@wei-desktop bash-learning]$ echo ${aa##*.}
world
[wei@wei-desktop bash-learning]$ echo ${aa%.*}
abc.xyz.hello
[wei@wei-desktop bash-learning]$ echo ${aa%%.*}
abc
[wei@wei-desktop bash-learning]$ echo ${aa/./-}
abc-xyz.hello.world
[wei@wei-desktop bash-learning]$ echo ${aa//./-}
abc-xyz-hello-world

  圖案匹配經常用於檔名的處理,例如去除路徑名,獲取檔案字尾或者字首等等。

  檢視extglob的選項是否開啟:shopt | grep extglob,如果開啟,可以使用或擴充套件的樣式匹配。開啟方式shopt -s exglob,關閉使用-u。可以用這些來替代萬用字元:

  • *(patternlist ) ,其中paternlist的格式為pattern1|pattern2|pattern3|….,表示匹配0個或者多個pattern
  • +(patternlist ) ,表示匹配1個或者多個pattern
  • ?(patternlist ) ,表示匹配0個或者1個pattern
  • @(patternlist ) ,表示匹配1個pattern
  • !(patternlist ) ,表示不匹配任何的pattern

  例子,echo ${aa//+(abc|hello)/ALICE}的值為ALICE.xyz.ALICE.world

長度操作

  ${#varname } ,例如上面的例子中${#aa}為19。

command substutuion:使用命令的輸入作為賦值

  可以通過command substitution 來設定引數的值。允許將命令的輸出作為變數的賦值。在makefile的編寫中,我們曾使用類似的方式即`pkg-config clutter-1.0 --libs`,這裡用``包含的內容就是命令執行的輸出結果。但是這種方式是為了和舊版本相容,可以使用$(UNIX command )的方式。這種方式可以巢狀的,及裡面的UNIX command也可以是command substitution。但是使用``的方式無法實現巢狀,下面是一些例子:

$(ls $(pwd)),給出當前目錄的檔案。例如$(ls $HOME),給出使用者目錄~下面的檔案。 例如type -all -path command給出命令的路徑,如果我們需要仔細檢視相關檔案屬性,可以使用ls -l $(type -all -path vi)。 vi $(grep -l 'command substitution' ch*),表示編輯當前目錄開ch大頭的含有'command substitution'內容的檔案,其中-來表示,只顯示目標檔案。

cut和awk的用法:獲取列資訊

  這兩個適用於獲得列的方式,舊的BSD系統不提供cut,需要使用awk來替代。使用方式cut –fN –dC filename或者awk –FC '{print $N}' filename。其中N表示列出,C表示分割符號,預設為tab。如果我們使用空格,可以為’ ‘,如果使用|等或產生奇異的特殊符合用/|的方式。例如顯示使用者名稱cat /etc/passwd | cut –f1 –d:。對於命令在stdout的輸出,使用空格對其,例如who,我們可以使用引數-cX-Y的方式,表示顯示為開始的第X個字元到第Y個字元,X從1開始,如果沒有Y,表示一直顯示到最後。例如who | cut –c10-15

一個stack的小例子

  下面我們給出一個FILO的stack例子,用來複習string的操作。

push_func()
{
   #注意如果沒有給出func的引數,則在func中跳出,而不是終結整個指令碼
    entry=${1:?"Please enter the entry as push_func param"}
    #注意在bottow後面有一個空格,我們使用空格作為分割,這是為了pop最後一個entry用
    mystack="$entry ${mystack:-bottow }"
    echo "push $entry in stack : $mystack"
}

pop_func()
{
    #刪除最top的entry
    mystack=${mystack#*' '}
   #獲取當前stack的top元素
    entry=${mystack%% *}
    echo "After pop, top entry is '$entry', stack is $mystack"
}

push_func one
push_func
push_func two
pop
pop
pop

相關連結: 我的Linux操作相關文章

相關文章