国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
shell編程范例之字符串操作 - wuye_chinaunix
shell編程范例之字符串操作
falcon<zhangjinw@gmail.com>
2007-11-17
忙活了一個(gè)禮拜,終于等到周末,可以空下來(lái)寫(xiě)點(diǎn)東西。
這次介紹 _字符串操作_ 了,這里先得明白兩個(gè)東西,什么是字符串,對(duì)字符串有哪些操作?
下面是"在線新華字典"的解釋:
字符串:
簡(jiǎn)稱“串”。有限字符的序列。數(shù)據(jù)元素為字符的線性表,是一種數(shù)據(jù)的邏輯結(jié)構(gòu)。在計(jì)算機(jī)中可有不同的存儲(chǔ)結(jié)構(gòu)。在串上可進(jìn)行求子串、插入字符、刪除字符、置換字符等運(yùn)算。
而字符呢?
字符:
計(jì)算機(jī)程序設(shè)計(jì)及操作時(shí)使用的符號(hào)。包括字母、數(shù)字、空格符、提示符及各種專用字符等。
照這樣說(shuō),之前介紹的數(shù)值操作中的數(shù)字,邏輯運(yùn)算中的真假值,都是以字符的形式呈現(xiàn)出來(lái)的,是一種特別的字符,對(duì)它們的運(yùn)算只不過(guò)是字符操作的特例罷了。而這里將研究一般字符的運(yùn)算,它具有非常重要的意義,因?yàn)閷?duì)我們來(lái)說(shuō),一般的工作都是處理字符而已。這些運(yùn)算實(shí)際上將圍繞上述兩個(gè)定義來(lái)做。
第一、找出字符或者字符串的類(lèi)型,是數(shù)字、字母還是其他特定字符,是可打印字符,還是不可打印字符(一些控制字符)。
第二、找出組成字符串的字符個(gè)數(shù)和字符串的存儲(chǔ)結(jié)構(gòu)(比如數(shù)組)。
第三、對(duì)串的常規(guī)操作:求子串、插入字符、刪除字符、置換字符、字符串的比較等。
第四、對(duì)串的一些比較復(fù)雜而有趣的操作,這里將在最后介紹一些有趣的范例。
1. 字符串的屬性
1.1 字符串的類(lèi)型
字符有可能是數(shù)字、字母、空格、其他特殊字符,而字符串有可能是它們?nèi)魏我环N或者多種的組合,在組合之后還可能形成一個(gè)具有特定意義的字符串,諸如郵件地址,URL地址等。
概要示例: 下面我們來(lái)看看如何判斷字符的類(lèi)型。
// 數(shù)字或者數(shù)字組合(能夠返回結(jié)果,即程序退出狀態(tài)是0,說(shuō)明屬于這種類(lèi)型,反之不然)
$ i=5;j=9423483247234;
$ echo $i | grep [0-9]*
5
$ echo $j | grep [0-9]*
9423483247234
$ echo $j | grep [0-9]* >/dev/null
$ echo $?
0
// 字符組合(小寫(xiě)字母、大寫(xiě)字母、兩者的組合)
$ c="A"; d="fwefewjuew"; e="fewfEFWefwefe"
$ echo $c | grep [A-Z]
A
$ echo $d | grep "[a-z]*"
fwefewjuew
$ echo $e | grep "[a-zA-Z]*"
fewfEFWefwefe
// 字母和數(shù)字的組合
$ ic="432fwfwefeFWEwefwef"
$ echo $ic | grep "[0-9a-zA-Z]*"
432fwfwefeFWEwefwef
// 空格或者Tab鍵等
$ echo " " | grep " "
$ echo -e "\t" | grep "[[:space:]]" #[[:space:]]會(huì)同時(shí)匹配空格和TAB鍵
$ echo -e " \t" | grep "[[:space:]]"
$ echo -e "\t" | grep "<tab>" #<tab>為在鍵盤(pán)上按下TAB鍵,而不是字符<tab>
// 匹配郵件地址
$ echo "test2007@lzu.cn" | grep "[0-9a-zA-Z\.]*@[0-9a-zA-Z\.]"
test2007@lzu.cn
// 匹配URL地址(以http鏈接為例)
$ echo "http://news.lzu.edu.cn/article.jsp?newsid=10135" | grep "http://[0-9a-zA-Z\./=?]*"
http://news.lzu.edu.cn/article.jsp?newsid=10135
說(shuō)明:
[1] /dev/null和/dev/zero是非常有趣的兩個(gè)設(shè)備,它們都猶如一個(gè)黑洞,什么東西掉進(jìn)去都會(huì)消失殆盡;后者則是一個(gè)能源箱,你總能從那里取到0,直到你退出。兩者的部分用法見(jiàn):關(guān)于zero及NULL設(shè)備的一些問(wèn)題
[2] [[:space:]]是grep用于匹配空格或者TAB鍵類(lèi)型字符串的一種標(biāo)記,其他類(lèi)似的標(biāo)記請(qǐng)查看grep的幫助,man grep。
[3] 上面都是用grep來(lái)進(jìn)行模式匹配,實(shí)際上sed, awk都可以用來(lái)做模式匹配,關(guān)于匹配中用到的正則匹配模式知識(shí),大家可以參考正則匹配模式,更多相關(guān)資料請(qǐng)看參考資料。
[4] 如果僅僅想判斷字符串是否為空,即判斷字符串的長(zhǎng)度是否為零,那么可以簡(jiǎn)單的通過(guò)test命令的-z選項(xiàng)來(lái)判斷,具體用法見(jiàn)test命令,man test.
概要示例: 判斷字符是否可打?。咳绾慰刂谱址诮K端的顯示。
// 用grep判斷某個(gè)字符是否為可打印字符
$ echo "\t\n" | grep "[[:print:]]"
\t\n
$ echo $?
0
$ echo -e "\t\n" | grep "[[:print:]]"
$ echo $?
1
// 用echo的-e選項(xiàng)在屏幕控制字符顯示位置、顏色、背景等
$ echo -e "\33[31;40m" #設(shè)置前景色為黑色,背景色為紅色
$ echo -e "\33[11;29H Hello, World\!" #在屏幕的第11行,29列開(kāi)始打印字符串Hello,World!
// 在屏幕的某個(gè)位置動(dòng)態(tài)顯示當(dāng)前系統(tǒng)時(shí)間
$ while :; do echo -e "\33[11;29H "$(date "+%Y-%m-%d %H:%M:%S"); done
// 用col命令過(guò)濾掉某些控制字符,在處理諸如script,screen等截屏命令的輸出結(jié)果時(shí),很有用
$ screen -L
$ cat /bin/cat
$ exit
$ cat screenlog.0 | col -b   # 把一些控制字符過(guò)濾后,就可以保留可讀的操作日志
更多關(guān)于字符在終端的顯示控制方法,請(qǐng)參考資料[20]和字符顯示實(shí)例[21]:用shell實(shí)現(xiàn)的一個(gè)動(dòng)態(tài)時(shí)鐘。
1.2 字符串的長(zhǎng)度
概要示例: 除了組成字符串的字符類(lèi)型外,字符串還有哪些屬性呢?組成字符串的字符個(gè)數(shù)。下面我們來(lái)計(jì)算字符串的長(zhǎng)度,即所有字符的個(gè)數(shù),并簡(jiǎn)單介紹幾種求字符串中指定字符個(gè)數(shù)的方法。
// 計(jì)算某個(gè)字符串的長(zhǎng)度,即所有字符的個(gè)數(shù)[這計(jì)算方法是五花八門(mén),擇其優(yōu)著而用之]
$ var="get the length of me"
$ echo ${var}     # 這里等同于$var
get the length of me
$ echo ${#var}
20
$ expr length "$var"
20
$ echo $var | awk '{printf("%d\n", length($0));}'
20
$ echo -n $var |  wc -c
20
// 計(jì)算某些指定一個(gè)字符或者多個(gè)字符的個(gè)數(shù)
$ echo $var | tr -cd g | wc -c
2
$ echo -n $var | sed -e 's/[^g]//g' | wc -c
2
$ echo -n $var | sed -e 's/[^gt]//g' | wc -c
5
// 如果要統(tǒng)計(jì)單詞個(gè)數(shù),更多相關(guān)信息見(jiàn)《shell編程之?dāng)?shù)值計(jì)算》之 _單詞統(tǒng)計(jì)_ 實(shí)例。
$ echo $var | wc -w
5
$ echo "$var" | tr " " "\n" | grep get | uniq -c
1
$ echo "$var" | tr " " "\n" | grep get | wc -l
1
說(shuō)明:
${}操作符在Bash里頭一個(gè)“大牛”,能勝任相當(dāng)多的工作,具體就看看網(wǎng)中人的《shell十三問(wèn)》之《Shell十三問(wèn)》之"$(( )) 與 $( ) 還有${ } 差在哪?" 吧。
1.3 字符串的存儲(chǔ)
在我們看來(lái),字符串是一連串的字符而已,但是為了操作方便,我們往往可以讓字符串呈現(xiàn)出一定的結(jié)構(gòu)。在這里,我們不關(guān)心字符串在內(nèi)存中的實(shí)際存儲(chǔ)結(jié)構(gòu),僅僅關(guān)系它呈現(xiàn)出來(lái)的邏輯結(jié)構(gòu)。比如,這樣一個(gè)字符串:"get the length of me",我們可以從不同的方面來(lái)呈現(xiàn)它。
1.3.1 通過(guò)字符在串中的位置來(lái)呈現(xiàn)它
這樣我們就可以通過(guò)指定位置來(lái)找到某個(gè)子串。這在c語(yǔ)言里頭通常可以利用指針來(lái)做。而在shell編程中,有很多可用的工具,諸如expr,awk都提供了類(lèi)似的方法來(lái)實(shí)現(xiàn)子串的查詢動(dòng)作。兩者都幾乎支持模式匹配(match)和完全匹配(index)。這在后面的字符串操作中將詳細(xì)介紹。
1.3.2 根據(jù)某個(gè)分割符來(lái)取得字符串的各個(gè)部分
這里最常見(jiàn)的就是行分割符、空格或者TAB分割符了,前者用來(lái)當(dāng)行號(hào),我們似乎已經(jīng)司空見(jiàn)慣了,因?yàn)槲覀兊木庉嬈骶瓦@樣“莫名”地處理著行分割符(在 unix下為\n,在其他系統(tǒng)下有一些不同,比如windows下為\r\n)。而空格或者TAB鍵經(jīng)常用來(lái)分割數(shù)據(jù)庫(kù)的各個(gè)字段,這似乎也是司空見(jiàn)慣的事情。
正是因?yàn)檫@樣,所以產(chǎn)生了大量?jī)?yōu)秀的行編輯工具,諸如grep,awk,sed等。在“行內(nèi)”(姑且這么說(shuō)吧,就是處理單行,即字符串里頭不再包含行分割符)的字符串分割方面,cut和awk提供了非常優(yōu)越的“行內(nèi)”(處理單行)處理能力。
1.3.3 更方便地處理用分割符分割好的各個(gè)部分
同樣是用到分割符,但為了更方便的操作分割以后的字符串的各個(gè)部分,我們抽象了“數(shù)組”這么一個(gè)數(shù)據(jù)結(jié)構(gòu),從而讓我們更加方便地通過(guò)下標(biāo)來(lái)獲取某個(gè)指定的部分。bash提供了這么一種數(shù)據(jù)結(jié)構(gòu),而優(yōu)秀的awk也同樣提供了它,我們這里將簡(jiǎn)單介紹它們的用法。
概要示例:利用數(shù)組存放"get the length of me"的用空格分開(kāi)的各個(gè)部分。
//1. bash提供的數(shù)組數(shù)據(jù)結(jié)構(gòu),它是以數(shù)字為下標(biāo)的,和C語(yǔ)言從0開(kāi)始的下標(biāo)一樣
$ var="get the length of me"
$ var_arr=($var)    #這里把字符串var存放到字符串?dāng)?shù)組var_arr中了,默認(rèn)以空格作為分割符
$ echo ${var_arr[0]} ${var_arr[1]} ${var_arr[2]} ${var_arr[3]} ${var_arr[4]}
get the length of me
$ echo ${var_arr[@]}    #這個(gè)就是整個(gè)字符串所有部分啦,這里可以用*代替@,下同
get the length of me
$ echo ${#var_arr[@]}    #記得上面求某個(gè)字符串的長(zhǎng)度么,#操作符,如果想求某個(gè)數(shù)組元素的字符串長(zhǎng)度,那么就把@換成下標(biāo)吧
5
// 你也可以直接給某個(gè)數(shù)組元素賦值
$ var_arr[5]="new_element"
$ echo ${var_arr[5]}
6
$ echo ${var_arr[5]}
new_element
// bash里頭實(shí)際上還提供了一種類(lèi)似于“數(shù)組”的功能,即"for i in 用指定分割符分開(kāi)的字符串" 的用法
// 即,你可以很方便的獲取某個(gè)字符串的某個(gè)部分
$  for i in $var; do echo -n $i" "; done;
get the length of me
//2. awk里頭的數(shù)組,注意比較它和bash提供的數(shù)組的異同
// split把一行按照空格分割,存放到數(shù)組var_arr中,并返回?cái)?shù)組的長(zhǎng)度。注意:這里的第一個(gè)元素下標(biāo)不是0,而是1
$ echo $var | awk '{printf("%d %s\n", split($0, var_arr, " "), var_arr[1]);}'
5 get
// 實(shí)際上,上面的操作很類(lèi)似awk自身的行處理功能:awk默認(rèn)把一行按照空格分割為多個(gè)域,并可以通過(guò)$1,$2,$3...來(lái)獲取,$0表示整行
// 這里的NF是該行的域的總數(shù),類(lèi)似于上面數(shù)組的長(zhǎng)度,它同樣提供了一種通過(guò)“下標(biāo)”訪問(wèn)某個(gè)字符串的功能
$ echo $var | awk '{printf("%d | %s %s %s %s %s | %s\n", NF, $1, $2, $3, $4, $5, $0);}'
5 | get the length of me | get the length of me
// awk的“數(shù)組”功能何止于此呢,看看它的for引用吧,注意,這個(gè)和bash里頭的for不太一樣,i不是元素本身,而是下標(biāo)
$ echo $var | awk '{split($0, var_arr, " "); for(i in var_arr) printf("%s ",var_arr);}'
get the length of me
$ echo $var | awk '{split($0, var_arr, " "); for(i in var_arr) printf("%s ",i);}'
1 2 3 4 5
// awk還有更“厲害”的處理能力,它的下標(biāo)可以不是數(shù)字,而可以是字符串,從而變成了“關(guān)聯(lián)”數(shù)組,這種“關(guān)聯(lián)”的作用在某些方便將讓我們非常方便
// 比如,我們這里就實(shí)現(xiàn)一個(gè)非凡的應(yīng)用,把某個(gè)文件中的某個(gè)系統(tǒng)調(diào)用名替換成地址,如果你真正用起它,你會(huì)感慨它的“鬼斧神工”的。
// 這就是我在一個(gè)場(chǎng)合最好才發(fā)現(xiàn)的隨好的實(shí)現(xiàn)方案:有興趣看看awk手冊(cè)帖子中我在3樓回復(fù)的實(shí)例吧。
$ cat symbol
sys_exit
sys_read
sys_close
$ ls /boot/System.map*
$ awk '{if(FILENAME ~ "System.map") map[$3]=$1; else {printf("%s\n", map[$1])}}' /boot/System.map-2.6.20-16-generic symbol
c0129a80
c0177310
c0175d80
// 另外,awk還支持刪除某個(gè)數(shù)組元素,如果你不用了就可以用delete函數(shù)給刪除掉。如果某些場(chǎng)合有需要的話,別忘了awk還支持二維數(shù)組。
okay,就介紹到這里啦。為什么要介紹這些內(nèi)容?再接著看下面的內(nèi)容,你就會(huì)發(fā)現(xiàn),那些有些的工具是怎么產(chǎn)生和發(fā)展起來(lái)的了,如果累了,看看最后一篇參考資料吧,它介紹了一些linux命令名字的由來(lái),說(shuō)不定可以幫助你理解本節(jié)下面的部分呢。
2. 字符串常規(guī)操作
字符串操作包括取子串、查詢子串、插入子串、刪除子串、子串替換、子串比較、子串排序、子串進(jìn)制轉(zhuǎn)換、子串編碼轉(zhuǎn)換等。
2.1 取子串
概要示例:取子串的方法主要有:直接到指定位置求子串,字符匹配求子串。
// 按照位置取子串,比如從什么位置開(kāi)始,取多少個(gè)字符
$ var="get the length of me"
$ echo ${var:0:3}
get
$ echo ${var:(-2)}   # 方向相反呢
me
$ echo `expr substr "$var" 5 3` #記得把$var引起來(lái),否則expr會(huì)因?yàn)榭崭穸馕鲥e(cuò)誤
the
$ echo $var | awk '{printf("%s\n", substr($0, 9, 6))}'
length
// 匹配字符求子串
$ echo ${var%% *} #從右邊開(kāi)始計(jì)算,刪除最左邊的空格右邊的所有字符
get
$ echo ${var% *} #從右邊開(kāi)始計(jì)算,刪除第一個(gè)空格右邊的所有字符
get the length of
$ echo ${var##* }  #從左邊開(kāi)始計(jì)算,刪除最右邊的空格左邊的所有字符
me
$ echo ${var#* }  #從左邊開(kāi)始計(jì)算,刪除第一個(gè)空格左邊的所有字符
the length of me
$ echo $var | awk '{printf("%s\n", $1);}' # awk把$var按照空格分開(kāi)為多個(gè)變量,依次為$1,$2,$3,$4,$5
get
$ echo $var | awk '{printf("%s\n", $5);}'
me
$ echo $var | cut -d" " -f 5  #差點(diǎn)把cut這個(gè)小東西忘記啦,用起來(lái)和awk類(lèi)似, -d指定分割符,如同awk用-F指定分割符一樣,-f指定“域”,如同awk的$數(shù)字。
$ echo $var | sed 's/ [a-z]*//g'  #刪除所有 空格+字母串 的字符串,所以get后面的全部被刪除了
get
$ echo $var | sed 's/[a-z]* //g'
me
$ echo $var | tr " " "\n" | sed -n 1p #sed有按地址(行)打印(p)的功能,記得先用tr把空格換成行號(hào)
get
$ echo $var | tr " " "\n" | sed -n 5p
me
// tr也可以用來(lái)取子串哦,它也可以類(lèi)似#和%來(lái)“拿掉”一些字符串來(lái)實(shí)現(xiàn)取子串
$ echo $var | tr -d " "
getthelengthofme
$ echo $var | tr -cd "[a-z]" #把所有的空格都拿掉了,僅僅保留字母字符串,注意-c和-d的用法
getthelengthofme
說(shuō)明:
[1] %和#的區(qū)別是,刪除字符的方向不一樣,前者在右,后者在左,%%和%,##和#的方向是前者是最大匹配,后者是最小匹配。(好的記憶方法見(jiàn)網(wǎng)中人的鍵盤(pán)記憶法:#$%是鍵盤(pán)依次從左到右的三個(gè)鍵)
[2] tr的-c選項(xiàng)是complement的縮寫(xiě),即invert,而-d選項(xiàng)是刪除的意思,tr -cd "[a-z]"這樣一來(lái)就變成保留所有的字母啦。
對(duì)于字符串的截取,實(shí)際上還有一些命令,如果head,tail等可以實(shí)現(xiàn)有意思的功能,可以截取某個(gè)字符串的前面、后面指定的行數(shù)或者字節(jié)數(shù)。例如:
$ echo "abcdefghijk" | head -c 4
abcd
$ echo -n "abcdefghijk" | tail -c 4
hijk
2.2. 查詢子串
概要示例:子串查詢包括:返回符合某個(gè)模式的子串本身和返回子串在目標(biāo)串中的位置。
準(zhǔn)備:在進(jìn)行下面的操作之前,請(qǐng)把http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1385.html鏈接中的內(nèi)容復(fù)制到一個(gè)文本text里頭,用于下面的操作。
// 查詢子串在目標(biāo)串中的位置
$ var="get the length of me"
$ expr index "$var" t        #貌似僅僅可以返回某個(gè)字符或者多個(gè)字符中第一個(gè)字符出現(xiàn)的位置
3
$ echo $var | awk '{printf("%d\n", match($0,"the"));}'    #awk卻能找出字串,match還可以匹配正則表達(dá)式
5
// 查詢子串,返回包含子串的行(awk,sed都可以實(shí)現(xiàn)這些功能,但是grep最擅長(zhǎng))
$ grep "consists of" text   # 查詢text文件包含consists of的行,并打印這些行
$ grep "consists[[:space:]]of" -n -H text # 打印文件名,子串所在行的行號(hào)和該行的內(nèi)容
$ grep "consists[[:space:]]of" -n -o text # 僅僅打印行號(hào)和匹配到的子串本身的內(nèi)容
$ awk '/consists of/{ printf("%s:%d:%s\n",FILENAME, FNR, $0)}' text  #看到?jīng)]?和grep的結(jié)果一樣
$ sed -n -e '/consists of/=;/consists of/p' text #同樣可以打印行號(hào)
說(shuō)明:
[1] awk,grep,sed都能通過(guò)模式匹配查找指定的字符串,但是它們各有擅長(zhǎng)的領(lǐng)域,我們將在后續(xù)的章節(jié)中繼續(xù)使用和比較它們,從而發(fā)現(xiàn)各自的優(yōu)點(diǎn)。
[2] 在這里我們姑且把文件內(nèi)容當(dāng)成了一個(gè)大的字符串,在后面的章節(jié)中我們將專門(mén)介紹文件的操作,所以對(duì)文件內(nèi)容中存放字符串的操作將會(huì)有更深入的分析和介紹。
2.3. 子串替換
子串替換就是把某個(gè)指定的子串替換成其他的字符串,實(shí)際上這里就蘊(yùn)含了“插入子串”和“刪除子串”的操作。例如,你想插入某個(gè)字符串到某個(gè)子串之前,就可以把原來(lái)的子串替換成”子串+新的字符串“,如果想刪除某個(gè)子串,就把子串替換成空串。不過(guò)有些工具提供了一些專門(mén)的用法來(lái)做插入子串和刪除子串的操作,所以呆伙還是會(huì)專門(mén)介紹的。另外,要想替換掉某個(gè)子串,一般都是先找到子串(查詢子串),然后再把它替換掉的,實(shí)質(zhì)上很多工具在使用和設(shè)計(jì)上都體現(xiàn)了這么一點(diǎn)。
概要示例:下面我們把變量var中的空格替換成下劃線看看。
// 用{}運(yùn)算符,還記得么?網(wǎng)中人的教程。
$ var="get the length of me"
$ echo ${var/ /_}        #把第一個(gè)空格替換成下劃線
get_the length of me
$ echo ${var// /_}        #把所有空格都替換成了下劃線了
get_the_length_of_me
// 用awk,awk提供了轉(zhuǎn)換的最小替換函數(shù)sub和全局替換函數(shù)gsub,類(lèi)似/和//
$ echo $var | awk '{sub(" ", "_", $0); printf("%s\n", $0);}'
get_the length of me
$ echo $var | awk '{gsub(" ", "_", $0); printf("%s\n", $0);}'
get_the_length_of_me
// 用sed了,子串替換可是sed的特長(zhǎng)
$ echo $var | sed -e 's/ /_/'    #s <= substitude
get_the length of me
$ echo $var | sed -e 's/ /_/g'    #看到?jīng)]有,簡(jiǎn)短兩個(gè)命令就實(shí)現(xiàn)了最小匹配和最大匹配g <= global
get_the_length_of_me
// 有忘記tr命令么?可以用替換單個(gè)字符的
$ echo $var | tr " " "_"
get_the_length_of_me
$ echo $var | tr '[a-z]' '[A-Z]'   #這個(gè)可有意思了,把所有小寫(xiě)字母都替換為大寫(xiě)字母
GET THE LENGTH OF ME
說(shuō)明:sed還有很有趣的標(biāo)簽用法呢,下面再介紹吧。
有一種比較有意思的字符串替換是,整個(gè)文件行的倒置,這個(gè)可以通過(guò)tac命令實(shí)現(xiàn),它會(huì)把文件中所有的行全部倒轉(zhuǎn)過(guò)來(lái)。在一定意義上來(lái)說(shuō),排序?qū)嶋H上也是一個(gè)字符串替換。
2.4. 插入子串
插入子串:就是在指定的位置插入子串,這個(gè)位置可能是某個(gè)子串的位置,也可能是從某個(gè)文件開(kāi)頭算起的某個(gè)長(zhǎng)度。通過(guò)上面的練習(xí),我們發(fā)現(xiàn)這兩者之間實(shí)際上是類(lèi)似的。
公式:插入子串=把"old子串"替換成"old子串+new子串"或者"new子串+old子串"
概要示例::下面在var字符串的空格之前或之后插入一個(gè)下劃線
// 用{}
$ var="get the length of me"
$ echo ${var/ /_ }        #在指定字符串之前插入一個(gè)字符串
get_ the length of me
$ echo ${var// /_ }
get_ the_ length_ of_ me
$ echo ${var/ / _}        #在指定字符串之后插入一個(gè)字符串
get _the length of me
$ echo ${var// / _}
get _the _length _of _me
// 其他的還用演示么?這里主要介紹sed怎么用來(lái)插入字符吧,因?yàn)樗臉?biāo)簽功能很有趣
$ echo $var | sed -e 's/\( \)/_\1/' #\(和\)將不匹配到的字符串存放為一個(gè)標(biāo)簽,按匹配順序?yàn)閈1,\2...
get_ the length of me
$ echo $var | sed -e 's/\( \)/_\1/g'
get_ the_ length_ of_ me
$ echo $var | sed -e 's/\( \)/\1_/'
get _the length of me
$ echo $var | sed -e 's/\( \)/\1_/g'
get _the _length _of _me
// 看看sed的標(biāo)簽的順序是不是\1,\2....,看到?jīng)]?\2和\1掉換位置后,the和get的位置掉換了
$ echo $var | sed -e 's/\([a-z]*\) \([a-z]*\) /\2 \1 /g'
the get of length me
// sed還有專門(mén)的插入指令,a和i,分別表示在匹配的行后和行前插入指定字符
$ echo $var | sed '/get/a test'
get the length of me
test
$ echo $var | sed '/get/i test'
test
get the length of me
2.5. 刪除子串
刪除子串:應(yīng)該很簡(jiǎn)單了吧,把子串替換成“空”(什么都沒(méi)有)不就變成了刪除么。還是來(lái)簡(jiǎn)單復(fù)習(xí)一下替換吧。
概要示例::把var字符串中所有的空格給刪除掉。
鼓勵(lì): 這樣一替換不知道變成什么單詞啦,誰(shuí)認(rèn)得呢?但是中文卻是連在一起的,所以中文有多難,你想到了么?原來(lái)你也是個(gè)語(yǔ)言天才,而英語(yǔ)并不可怕,你有學(xué)會(huì)它的天賦,只要你有這個(gè)打算。
// 再用{}
$ echo ${var// /}
getthelengthofme
// 再用awk
$ echo $var | awk '{gsub(" ","",$0); printf("%s\n", $0);}'
// 再用sed
$ echo $var | sed 's/ //g'
getthelengthofme
// 還有更簡(jiǎn)單的tr命令,tr也可以把" "給刪除掉,看
$ echo $var | tr -d " "
getthelengthofme
如果要?jiǎng)h除掉第一個(gè)空格后面所有的字符串該怎么辦呢?還記得{}的#和%用法么?如果不記得,回到這一節(jié)的還頭開(kāi)始復(fù)習(xí)吧。(實(shí)際上刪除子串和取子串未嘗不是兩種互補(bǔ)的運(yùn)算呢,刪除掉某些不想要的子串,也就同時(shí)取得另外那些想要的子串——這個(gè)世界就是一個(gè)“二元”的世界,非常有趣)
2.6. 子串比較
這個(gè)很簡(jiǎn)單:還記得test命令的用法么?man test。它可以用來(lái)判斷兩個(gè)字符串是否相等的。另外,你發(fā)現(xiàn)了“字符串是否相等”和“字符串能否跟另外一個(gè)字符串匹配"兩個(gè)問(wèn)題之間的關(guān)系嗎?如果兩個(gè)字符串完全匹配,那么這兩個(gè)字符串就相等了。所以呢,上面用到的字符串匹配方法,也同樣可以用到這里。
2.7. 子串排序
差點(diǎn)忘記這個(gè)重要的內(nèi)容了,子串排序可是經(jīng)常用到的,常見(jiàn)的有按字母序、數(shù)字序等正序或反序排列。sort命令可以用來(lái)做這個(gè)工作,它和其他行處理命令一樣,是按行操作的,另外,它類(lèi)似cut和awk,可以指定分割符,并指定需要排序的列。
$ var="get the length of me"
$ echo $var | tr ' ' '\n' | sort   #正序排
get
length
me
of
the
$ echo $var | tr ' ' '\n' | sort  -r #反序排
the
of
me
length
get
$ cat data.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
41 45 44 44 26 44 42 20 20 38 37 25 45 45 45
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
44 20 30 39 35 38 38 28 25 30 36 20 24 32 33
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
41 33 51 39 20 20 44 37 38 39 42 40 37 50 50
46 47 48 49 50 51 52 53 54 55 56
42 43 41 42 45 42 19 39 75 17 17
$ cat data.txt | sort -k 2 -n
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
44 20 30 39 35 38 38 28 25 30 36 20 24 32 33
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
41 33 51 39 20 20 44 37 38 39 42 40 37 50 50
42 43 41 42 45 42 19 39 75 17 17
41 45 44 44 26 44 42 20 20 38 37 25 45 45 45
46 47 48 49 50 51 52 53 54 55 56
2.7. 子串進(jìn)制轉(zhuǎn)換
如果字母和數(shù)字字符用來(lái)計(jì)數(shù),那么就存在進(jìn)制轉(zhuǎn)換的問(wèn)題。在數(shù)值計(jì)算一節(jié)的回復(fù)資料里,我們已經(jīng)介紹了bc命令,這里再簡(jiǎn)單的復(fù)習(xí)一下。
$ echo "ibase=10;obase=16;10" | bc
A
說(shuō)明:ibase指定輸入進(jìn)制,obase指出輸出進(jìn)制,這樣通過(guò)調(diào)整ibase和obase,你想怎么轉(zhuǎn)就怎么轉(zhuǎn)啦!
2.7. 子串編碼轉(zhuǎn)換
什么是字符編碼?這個(gè)就不用介紹了吧,看過(guò)那些亂七八糟顯示的網(wǎng)頁(yè)么?大多是因?yàn)闉g覽器顯示時(shí)的”編碼“和網(wǎng)頁(yè)實(shí)際采用的”編碼“不一致導(dǎo)致的。字符編碼通常是指把一序列”可打印“字符轉(zhuǎn)換成二進(jìn)制表示,而字符解碼呢則是執(zhí)行相反的過(guò)程,如果這兩個(gè)過(guò)程不匹配,則出現(xiàn)了所謂的”亂碼“。
為了解決”亂碼“問(wèn)題呢?就需要進(jìn)行編碼轉(zhuǎn)換。在linux下,我們可以使用iconv這個(gè)工具來(lái)進(jìn)行相關(guān)操作。這樣的情況經(jīng)常在不同的操作系統(tǒng)之間移動(dòng)文件,不同的編輯器之間交換文件的時(shí)候遇到,目前在windows下常用的漢字編碼是gb2312,而在linux下則大多采用utf8。
$ nihao_gb2312=$(echo "你好" | iconv -f utf8 -t gb2312)
$ echo $nihao_gb2312
???
$ nihao_utf8=$(echo $nihao_gb2312 | iconv -f gb2312 -t utf8)
$ PS1="$ "
$ echo $nihao_utf8
你好
說(shuō)明:我的終端默認(rèn)編碼是utf8,所以結(jié)果如上。
3. 字符串操作范例
實(shí)際上,在用Bash編程時(shí),大部分時(shí)間都是在處理字符串,因此把這一節(jié)熟練掌握非常重要。
3.1 處理一個(gè)非常有意義的字符串:URL地址
范例演示:處理URL地址
URL 地址(URL(Uniform Resoure Locator:統(tǒng)一資源定位器)是WWW頁(yè)的地址)幾乎是我們?nèi)粘I畹耐姘?,我們已?jīng)到了無(wú)法離開(kāi)它的地步啦,對(duì)它的操作很多,包括判斷URL地址的有效性,截取地址的各個(gè)部分(服務(wù)器類(lèi)型、服務(wù)器地址、端口、路徑等)并對(duì)各個(gè)部分進(jìn)行進(jìn)一步的操作。
下面我們來(lái)具體處理這個(gè)URL地址:
ftp://anonymous:ftp@mirror.lzu.edu.cn/software/scim-1.4.7.tar.gz
$ url="ftp://anonymous:ftp@mirror.lzu.edu.cn/software/scim-1.4.7.tar.gz"
// 匹配URL地址,判斷URL地址的有效性
$ echo $url | grep "ftp://[a-z]*:[a-z]*@[a-z\./-]*"
// 截取服務(wù)器類(lèi)型
$ echo ${url%%:*}
ftp
$ echo $url | cut -d":" -f 1
ftp
// 截取域名
$ tmp=${url##*@} ; echo ${tmp%%/*}
mirror.lzu.edu.cn
// 截取路徑
$ tmp=${url##*@} ; echo ${tmp%/*}
mirror.lzu.edu.cn/software
// 截取文件名
$ basename $url
scim-1.4.7.tar.gz
$ echo ${url##*/}
scim-1.4.7.tar.gz
// 截取文件類(lèi)型(擴(kuò)展名)
$ echo $url | sed -e 's/.*[0-9].\(.*\)/\1/g'
tar.gz
有了上面的知識(shí),我們就可以非常容易地進(jìn)行這些工作啦:修改某個(gè)文件的文件名,比如調(diào)整它的編碼,下載某個(gè)網(wǎng)頁(yè)里頭的所有pdf文檔等。這些就作為練習(xí)自己做吧,如果遇到問(wèn)題,可以在回帖交流。相應(yīng)地可以參考這個(gè)例子:
[1] 用腳本下載某個(gè)網(wǎng)頁(yè)中的英文原著(pdf文檔)
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1228.html
3.2 處理格式化的文本:/etc/passwd
平時(shí)做工作,大多數(shù)時(shí)候處理的都是一些“格式化”的文本,比如類(lèi)似/etc/passwd這樣的有固定行和列的文本,也有類(lèi)似tree命令輸出的那種具有樹(shù)形結(jié)構(gòu)的文本,當(dāng)然還有其他具有特定結(jié)構(gòu)的文本。
關(guān)于樹(shù)狀結(jié)構(gòu)的文本的處理,可以考慮看看這兩個(gè)例子:
[1] 用AWK轉(zhuǎn)換樹(shù)形數(shù)據(jù)成關(guān)系表
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1260.html
[2] 用Graphviz進(jìn)行可視化操作──繪制函數(shù)調(diào)用關(guān)系圖
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1425.html
實(shí)際上,只要把握好特性結(jié)構(gòu)的一些特點(diǎn),并根據(jù)具體的應(yīng)用場(chǎng)合,處理起來(lái)就不會(huì)困難。
下面我們來(lái)介紹具體有固定行和列的文本的操作,以/etc/passwd文件為例。關(guān)于這個(gè)文件的幫忙和用戶,請(qǐng)通過(guò)man 5 passwd查看。下面我們對(duì)這個(gè)文件以及相關(guān)的文件進(jìn)行一些有意義的操作。
// 選取/etc/passwd文件中的用戶名和組ID兩列
$ cat /etc/passwd | cut -d":" -f1,4
// 選取/etc/group文件中的組名和組ID兩列
$ cat /etc/group | cut -d":" -f1,3
// 如果想找出所有用戶所在的組,怎么辦?
$ join -o 1.1,2.1 -t":" -1 4 -2 3 /etc/passwd /etc/group
root:root
bin:bin
daemon:daemon
adm:adm
lp:lp
pop:pop
nobody:nogroup
falcon:users
// 先解釋一下:join命令用來(lái)連接兩個(gè)文件,有點(diǎn)類(lèi)似于數(shù)據(jù)庫(kù)的兩個(gè)表的連接。-t指定分割符,"-1 4 -2 3"指定按照第一個(gè)文件的第4列和第二個(gè)文件的第3列,即組ID進(jìn)行連接,"-o 1.1,2.1"表示僅僅輸出第一個(gè)文件的第一列和第二個(gè)文件的第一列,這樣就得到了我們要的結(jié)果,不過(guò),可惜的是,這個(gè)結(jié)果并不準(zhǔn)確,再進(jìn)行下面的操作,你就會(huì)發(fā)現(xiàn):
$ cat /etc/passwd | sort -t":" -n -k 4 > /tmp/passwd
$ cat /etc/group | sort -t":" -n -k 3 > /tmp/group
$ join -o 1.1,2.1 -t":" -1 4 -2 3 /tmp/passwd /tmp/group
halt:root
operator:root
root:root
shutdown:root
sync:root
bin:bin
daemon:daemon
adm:adm
lp:lp
pop:pop
nobody:nogroup
falcon:users
games:users
// 可以看到這個(gè)結(jié)果才是正確的,所以以后使用join千萬(wàn)要注意這個(gè)問(wèn)題,否則采取更保守的做法似乎更能保證正確性,更多關(guān)于文件連接的討論見(jiàn)參考資料[14]
上面涉及到了處理某格式化行中的指定列,包括截?。ㄈ鏢QL的select用法),連接(如SQL的join用法),排序(如SQL的order by用法),都可以通過(guò)指定分割符來(lái)拆分某個(gè)格式化的行,另外,“截取”的做法還有很多,不光是cut,awk,甚至通過(guò)IFS指定分割符的read命令也可以做到,例如:
$ IFS=":"; cat /etc/group | while read C1 C2 C3 C4; do echo $C1 $C3; done
因此,熟悉這些用法,我們的工作將變得非常靈活有趣。
到這里,需要做一個(gè)簡(jiǎn)單的練習(xí),如何把按照列對(duì)應(yīng)的用戶名和用戶ID轉(zhuǎn)換成按照行對(duì)應(yīng)的,即把類(lèi)似下面的數(shù)據(jù):
$ cat /etc/passwd | cut -d":" -f1,3 --output-delimiter=" "
root 0
bin 1
daemon 2
轉(zhuǎn)換成:
$ cat a
root    bin     daemon
0       1       2
并轉(zhuǎn)換回去,有什么辦法呢?記得諸如tr,paste,split等命令都可以使用。
參考方法:
*正轉(zhuǎn)換:先截取用戶名一列存入文件user,再截取用戶ID存入id,再把兩個(gè)文件用paste -s命令連在一起,這樣就完成了正轉(zhuǎn)換。
*逆轉(zhuǎn)換:先把正轉(zhuǎn)換得到的結(jié)果用split -1拆分成兩個(gè)文件,再把兩個(gè)拆分后的文件用tr把分割符"\t"替換成"\n",只有用paste命令把兩個(gè)文件連在一起,這樣就完成了逆轉(zhuǎn)換。
更多有趣的例子,可以參考該序列第一部分的回復(fù),即參考資料[16]的回復(fù),以及蘭大開(kāi)源社區(qū)鏡像站用的鏡像腳本,即參考資料[17],另外,參考資料[18]關(guān)于用Shell實(shí)現(xiàn)一個(gè)五筆反查小工具也值得閱讀和改進(jìn)。
*更多例子將逐步補(bǔ)充和完善。
參考和推薦資料:
[1] 《高級(jí)Bash腳本編程指南》之操作字符串
http://www.linuxpk.com/doc/abs/string-manipulation.html
[2] 《高級(jí)Bash腳本編程指南》之指定變量的類(lèi)型
http://www.linuxpk.com/doc/abs/declareref.html
[3] 《Shell十三問(wèn)》之$(( )) 與 $( ) 還有${ } 差在哪?
http://bbs.chinaunix.net/viewthread.php?tid=218853&extra=&page=7#pid1617953
[4] Regular Expressions - User guide
http://www.zytrax.com/tech/web/regex.htm
[5] Regular Expression Tutorial
http://analyser.oli.tudelft.nl/regex/index.html.en
[6] Grep Tutorial
http://www.panix.com/~elflord/unix/grep.html
[7] Sed Tutorial
http://www.panix.com/~elflord/unix/sed.html
[8] awk Tutorial
http://www.gnulamp.com/awk.html
[9] sed Tutorial
http://www.gnulamp.com/sed.html
[10] An awk Primer
http://www.vectorsite.net/tsawk.html
[11] 一些奇怪的 unix 指令名字的由來(lái)
http://www.linuxsir.org/bbs/showthread.php?t=24264
[12] 磨練構(gòu)建正則表達(dá)式模式的技能
http://www.ibm.com/developerworks/cn/aix/library/au-expressions.html
[13] 實(shí)用正則表達(dá)式
http://www.linuxlong.com/forum/bbs-27-1.html
[14] AWK使用手冊(cè) 3 樓的回復(fù)帖
http://oss.lzu.edu.cn/modules/newbb/viewtopic.php?topic_id=1006&forum=26
[15] 基礎(chǔ)11:文件分類(lèi)、合并和分割(sort,uniq,join,cut,paste,split)
http://blog.chinaunix.net/u/9465/showart_144700.html
[16] Shell編程范例之?dāng)?shù)值運(yùn)算
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1391.html
[17] 蘭大Mirror鏡像站的鏡像腳本
http://oss.lzu.edu.cn/blog/article.php?tid_1236.html
[18] 一個(gè)用Shell寫(xiě)的五筆反查小工具
http://oss.lzu.edu.cn/blog/blog.php?/do_showone/tid_1017.html
[19] 使用Linux 文本工具簡(jiǎn)化數(shù)據(jù)的提取
http://linux.chinaunix.net/docs/2006-09-22/2803.shtml
[20] 如何控制終端:光標(biāo)位置,字符顏色,背景,清屏...
http://oss.lzu.edu.cn/modules/newbb/viewtopic.php?topic_id=962&forum=13
[21] 在終端動(dòng)態(tài)顯示時(shí)間
http://oss.lzu.edu.cn/modules/newbb/viewtopic.php?topic_id=964&forum=26
后記:
[1] 這一節(jié)本來(lái)是上個(gè)禮拜該弄好的,但是這些天太忙了,到現(xiàn)在才寫(xiě)好一個(gè)“初稿”,等到有時(shí)間再補(bǔ)充具體的范例。這一節(jié)的范例應(yīng)該是最最有趣的,所有得好好研究一下幾個(gè)有趣的范例。
[2] 寫(xiě)完[1]貌似是1點(diǎn)多,剛check了一下錯(cuò)別字和語(yǔ)法什么的,再添加了一節(jié),即“字符串的存儲(chǔ)結(jié)構(gòu)”,到現(xiàn)在已經(jīng)快half past 2啦,晚安,朋友們。
[3] 26號(hào),添加“子串進(jìn)制轉(zhuǎn)換”和“子串編碼轉(zhuǎn)換”兩小節(jié)以及一個(gè)處理URL地址的范例。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
shell大全
Linux Shell 文本處理工具集錦大CC | 大CC
PHP substr(),substr函數(shù) 返回字符串的子串
運(yùn)維常用linux命令\shell技巧范例
linux Shell學(xué)習(xí)筆記第二天
總結(jié)JavaScript的正則與其他語(yǔ)言的不同之處
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服