字符串:php
字符:html
通常字符的運算包括:linux
1. 字符串的屬性git
字符有多是數字、字母、空格、其餘特殊字符,而字符串有多是它們任何一種或者多種的組合,在組合以後還可能造成一個具備特定意義的字符串,諸如郵件地址,URL地址等。
概要示例: 下面咱們來看看如何判斷字符的類型。正則表達式
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
31
32
33
34
35
|
//
數字或者數字組合(可以返回結果,即程序退出狀態是0,說明屬於這種類型,反之否則)
$ 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
//
字符組合(小寫字母、大寫字母、二者的組合)
$ 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
//
字母和數字的組合
$ ic=
"432fwfwefeFWEwefwef"
$
echo
$ic |
grep
"[0-9a-zA-Z]*"
432fwfwefeFWEwefwef
//
空格或者Tab鍵等
$
echo
" "
|
grep
" "
$
echo
-e
"\t"
|
grep
"[[:space:]]"
#[[:space:]]會同時匹配空格和TAB鍵
$
echo
-e
" \t"
|
grep
"[[:space:]]"
$
echo
-e
"\t"
|
grep
"<tab>"
#<tab>爲在鍵盤上按下TAB鍵,而不是字符<tab>
//
匹配郵件地址
$
echo
"test2007@lzu.cn"
|
grep
"[0-9a-zA-Z\.]*@[0-9a-zA-Z\.]"
test2007@lzu.cn
//
匹配URL地址(以http連接爲例)
http:
//news
.lzu.edu.cn
/article
.jsp?newsid=10135
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 用grep判斷某個字符是否爲可打印字符
$ echo
"\t\n"
| grep
"[[:print:]]"
\t\n
$ echo $?
0
$ echo -e
"\t\n"
| grep
"[[:print:]]"
$ echo $?
1
// 用echo的-e選項在屏幕控制字符顯示位置、顏色、背景等
$ echo -e
"\33[31;40m"
#設置前景色爲黑色,背景色爲紅色
$ echo -e
"\33[11;29H Hello, World\!"
#在屏幕的第
11
行,
29
列開始打印字符串Hello,World!
// 在屏幕的某個位置動態顯示當前系統時間
$
while
:;
do
echo -e
"\33[11;29H "
$(date
"+%Y-%m-%d %H:%M:%S"
); done
// 用col命令過濾掉某些控制字符,在處理諸如script,screen等截屏命令的輸出結果時,頗有用
$ screen -L
$ cat /bin/cat
$ exit
$ cat screenlog.
0
| col -b # 把一些控制字符過濾後,就能夠保留可讀的操做日誌
|
1.2 字符串的長度shell
概要示例: 除了組成字符串的字符類型外,字符串還有哪些屬性呢?組成字符串的字符個數。下面咱們來計算字符串的長度,即全部字符的個數,並簡單介紹幾種求字符串中指定字符個數的方法。數據庫
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
|
//
計算某個字符串的長度,即全部字符的個數[這計算方法是五花八門,擇其優着而用之]
$ 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
//
計算某些指定一個字符或者多個字符的個數
$
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
//
若是要統計單詞個數,更多相關信息見《shell編程之數值計算》之 _單詞統計_ 實例。
$
echo
$var |
wc
-w
5
$
echo
"$var"
|
tr
" "
"\n"
|
grep
get |
uniq
-c
1
$
echo
"$var"
|
tr
" "
"\n"
|
grep
get |
wc
-l
1
|
1
2
|
stringZ=abcABC123ABCabc
echo
`
expr
"$stringZ"
:
'.*'
`
# 15
|
${}操做符在Bash裏頭一個「大牛」,能勝任至關多的工做,具體就看看網中人的《shell十三問》之《Shell十三問》之"$(( )) 與 $( ) 還有${ } 差在哪?" 吧。編程
在一個文本文件的段落之間插入空行windows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#!/bin/bash
# paragraph-space.sh
# 在一個單倍行距的文本文件中插入空行.
# Usage: $0 <FILENAME
MINLEN=45
# 可能須要修改這個值.
# 假定行的長度小於$MINLEN所指定的長度的時候
#+ 才認爲此段結束.
while
read
line
# 提供和輸入文件同樣多的行...
do
echo
"$line"
# 輸入所讀入的行自己.
len=${
#line}
if
[
"$len"
-lt
"$MINLEN"
]
then
echo
# 在短行(譯者注: 也就是小於$MINLEN個字符的行)後面添加一個空行.
fi
done
exit
0
|
索引數組
expr index $string $substring
在字符串$string中所匹配到的$substring第一次所出現的位置.
1
2
3
4
5
6
|
stringZ=abcABC123ABCabc
echo
`
expr
index
"$stringZ"
C12`
# 6
# C 字符的位置.
echo
`
expr
index
"$stringZ"
1c`
# 3
# 'c' (in #3 position) matches before '1'.
|
這與C語言中的strchr()函數很是類似.
1.3 字符串的存儲
在咱們看來,字符串是一連串的字符而已,可是爲了操做方便,咱們每每可讓字符串呈現出必定的結構。在這裏,咱們不關心字符串在內存中的實際存儲結構,僅僅關係它呈現出來的邏輯結構。好比,這樣一個字符串:"get the length of me",咱們能夠從不一樣的方面來呈現它。
1.3.1 經過字符在串中的位置來呈現它
這樣咱們就能夠經過指定位置來找到某個子串。這在c語言裏頭一般能夠利用指針來作。而在shell編程中,有不少可用的工具,諸如expr,awk都提供了相似的方法來實現子串的查詢動做。二者都幾乎支持模式匹配(match)和徹底匹配(index)。這在後面的字符串操做中將詳細介紹。
匹配字符串開頭的子串長度
expr match "$string" '$substring'
$substring是一個正則表達式.
expr "$string" : '$substring'
$substring是一個正則表達式.
1
2
3
4
5
|
stringZ=abcABC123ABCabc
# |------|
echo
`
expr
match
"$stringZ"
'abc[A-Z]*.2'
`
# 8
echo
`
expr
"$stringZ"
:
'abc[A-Z]*.2'
`
# 8
|
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
//1
.
bash
提供的數組數據結構,它是以數字爲下標的,和C語言從0開始的下標同樣
$ var=
"get the length of me"
$ var_arr=($var)
#這裏把字符串var存放到字符串數組var_arr中了,默認以空格做爲分割符
$
echo
${var_arr[0]} ${var_arr[1]} ${var_arr[2]} ${var_arr[3]} ${var_arr[4]}
get the length of me
$
echo
${var_arr[@]}
#這個就是整個字符串全部部分啦,這裏能夠用*代替@,下同
get the length of me
$
echo
${
#var_arr[@]} #記得上面求某個字符串的長度麼,#操做符,若是想求某個數組元素的字符串長度,那麼就把@換成下標吧
5
//
你也能夠直接給某個數組元素賦值
$ var_arr[5]=
"new_element"
$
echo
${var_arr[5]}
6
$
echo
${var_arr[5]}
new_element
//
bash
裏頭實際上還提供了一種相似於「數組」的功能,即
"for i in 用指定分割符分開的字符串"
的用法
//
即,你能夠很方便的獲取某個字符串的某個部分
$
for
i
in
$var;
do
echo
-n $i
" "
;
done
;
get the length of me
//2
.
awk
裏頭的數組,注意比較它和
bash
提供的數組的異同
//
split
把一行按照空格分割,存放到數組var_arr中,並返回數組的長度。注意:這裏的第一個元素下標不是0,而是1
$
echo
$var |
awk
'{printf("%d %s\n", split($0, var_arr, " "), var_arr[1]);}'
5 get
//
實際上,上面的操做很相似
awk
自身的行處理功能:
awk
默認把一行按照空格分割爲多個域,並能夠經過$1,$2,$3...來獲取,$0表示整行
//
這裏的NF是該行的域的總數,相似於上面數組的長度,它一樣提供了一種經過「下標」訪問某個字符串的功能
$
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
的「數組」功能何止於此呢,看看它的
for
引用吧,注意,這個和
bash
裏頭的
for
不太同樣,i不是元素自己,而是下標
$
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
還有更「厲害」的處理能力,它的下標能夠不是數字,而能夠是字符串,從而變成了「關聯」數組,這種「關聯」的做用在某些方便將讓咱們很是方便
//
好比,咱們這裏就實現一個非凡的應用,把某個文件中的某個系統調用名替換成地址,若是你真正用起它,你會感慨它的「鬼斧神工」的。
//
這就是我在一個場合最好才發現的隨好的實現方案:有興趣看看
awk
手冊帖子中我在3樓回覆的實例吧。
$
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
還支持刪除某個數組元素,若是你不用了就能夠用delete函數給刪除掉。若是某些場合有須要的話,別忘了
awk
還支持二維數組。
|
概要示例:取子串的方法主要有:直接到指定位置求子串,字符匹配求子串。
${string:position}
在$string中從位置$position開始提取子串.
若是$string是"*"或者"@", 那麼將會提取從位置$position開始的位置參數.[1]
${string:position:length}
在$string中從位置$position開始提取$length長度的子串.
若是$string參數是"*"或"@", 那麼將會從$position位置開始提取$length個位置參數, 可是因爲可能沒有$length個位置參數了, 那麼就有幾個位置參數就提取幾個位置參數.
expr substr $string $position $length
在$string中從$position開始提取$length長度的子串.
expr match "$string" '\($substring\)'
從$string的開始位置提取$substring,$substring是正則表達式.
expr "$string" : '\($substring\)'
從$string的開始位置提取$substring,$substring是正則表達式.
expr match "$string" '.*\($substring\)'
從$string的結尾提取$substring,$substring是正則表達式.
expr "$string" : '.*\($substring\)'
從$string的結尾提取$substring,$substring是正則表達式.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//
按照位置取子串,好比從什麼位置開始,取多少個字符
$ var=
"get the length of me"
$
echo
${var:0:3}
get
$
echo
${var:(-2)}
# 方向相反呢
me
$
echo
`
expr
substr
"$var"
5 3`
#記得把$var引發來,不然expr會由於空格而解析錯誤
the
$
echo
$var |
awk
'{printf("%s\n", substr($0, 9, 6))}'
length
//
匹配字符求子串
$
echo
${var%% *}
#從右邊開始計算,刪除最左邊的空格右邊的全部字符
get
$
echo
${var% *}
#從右邊開始計算,刪除第一個空格右邊的全部字符
get the length of
$
echo
${var
##* } #從左邊開始計算,刪除最右邊的空格左邊的全部字符
me
$
echo
${var
#* } #從左邊開始計算,刪除第一個空格左邊的全部字符
the length of me
$
echo
$var |
awk
'{printf("%s\n", $1);}'
# awk把$var按照空格分開爲多個變量,依次爲$1,$2,$3,$4,$5
get
$
echo
$var |
awk
'{printf("%s\n", $5);}'
me
$
echo
$var |
cut
-d
" "
-f 5
#差點把cut這個小東西忘記啦,用起來和awk相似, -d指定分割符,如同awk用-F指定分割符同樣,-f指定「域」,如同awk的$數字。
$
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把空格換成行號
get
$
echo
$var |
tr
" "
"\n"
|
sed
-n 5p
me
//
tr
也能夠用來取子串哦,它也能夠相似
#和%來「拿掉」一些字符串來實現取子串
$
echo
$var |
tr
-d
" "
getthelengthofme
$
echo
$var |
tr
-
cd
"[a-z]"
#把全部的空格都拿掉了,僅僅保留字母字符串,注意-c和-d的用法
getthelengthofme
|
1
2
3
4
|
$ echo
"abcdefghijk"
| head -c
4
abcd
$ echo -n
"abcdefghijk"
| tail -c
4
hijk
|
2.2. 查詢子串
概要示例:子串查詢包括:返回符合某個模式的子串自己和返回子串在目標串中的位置。
準備:在進行下面的操做以前,請把http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1385.html 鏈 接中的內容複製到一個文本text裏頭,用於下面的操做。
// 查詢子串在目標串中的位置
$ var="get the length of me"
$ expr index "$var" t #貌似僅僅能夠返回某個字符或者多個字符中第一個字符出現的位置
3
$ echo $var | awk '{printf("%d\n", match($0,"the"));}' #awk卻能找出字串,match還能夠匹配正則表達式
5
// 查詢子串,返回包含子串的行(awk,sed均可以實現這些功能,可是grep最擅長)
$ grep "consists of" text # 查詢text文件包含consists of的行,並打印這些行
$ grep "consists[[:space:]]of" -n -H text # 打印文件名,子串所在行的行號和該行的內容
$ grep "consists[[:space:]]of" -n -o text # 僅僅打印行號和匹配到的子串自己的內容
$ awk '/consists of/{ printf("%s:%d:%s\n",FILENAME, FNR, $0)}' text #看到沒?和grep的結果同樣
$ sed -n -e '/consists of/=;/consists of/p' text #一樣能夠打印行號
2.3. 子串替換
子串替換就是把某個指定的子串替換成其餘的字符串,實際上這裏就蘊含了「插入子串」和「刪除子串」的操做。例如,你想插入某個字符串到某個子串之 前,就能夠把原來的子串替換成」子串+新的字符串「,若是想刪除某個子串,就把子串替換成空串。不過有些工具提供了一些專門的用法來作插入子串和刪除子串 的操做,因此呆夥仍是會專門介紹的。另外,要想替換掉某個子串,通常都是先找到子串(查詢子串),而後再把它替換掉的,實質上不少工具在使用和設計上都體 現了這麼一點。
${string/substring/replacement}
使用$replacement來替換第一個匹配的$substring.
${string//substring/replacement}
使用$replacement來替換全部匹配的$substring.
${string/#substring/replacement}
若是$substring匹配$string的開頭部分, 那麼就用$replacement來替換$substring.
${string/%substring/replacement}
若是$substring匹配$string的結尾部分, 那麼就用$replacement來替換$substring.
概要示例:下面咱們把變量var中的空格替換成下劃線看看。
// 用{}運算符,還記得麼?網中人的教程。
$ var="get the length of me"
$ echo ${var/ /_} #把第一個空格替換成下劃線
get_the length of me
$ echo ${var// /_} #把全部空格都替換成了下劃線了
get_the_length_of_me
// 用awk,awk提供了轉換的最小替換函數sub和全局替換函數gsub,相似/和//
$ 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的特長
$ echo $var | sed -e 's/ /_/' #s <= substitude
get_the length of me
$ echo $var | sed -e 's/ /_/g' #看到沒有,簡短兩個命令就實現了最小匹配和最大匹配g <= global
get_the_length_of_me
// 有忘記tr命令麼?能夠用替換單個字符的
$ echo $var | tr " " "_"
get_the_length_of_me
$ echo $var | tr '[a-z]' '[A-Z]' #這個可有意思了,把全部小寫字母都替換爲大寫字母
GET THE LENGTH OF ME
說明:sed還有頗有趣的標籤用法呢,下面再介紹吧。
有一種比較有意思的字符串替換是,整個文件行的倒置,這個能夠經過tac命令實現,它會把文件中全部的行所有倒轉過來。在必定意義上來講,排序實際 上也是一個字符串替換。
在替換子串時再提供一些tr的用法:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
tr
用來從標準輸入中經過替換或刪除操做,進行字符轉換。
tr
主要用於刪除文件中控制字符或進行字符轉換。使用
tr
時要轉換兩個字符串:字符串1用於查詢,字符串2用於處理各類轉換,
tr
剛執行時,字符串1中的字符被映射到字符串2中的字符,而後轉換操做開始。
一、用法和選項
用法:
tr
[選項]... SET1 [SET2]
說明:
tr
命令用於從標準輸入中替換、縮減和/或刪除字符,並將結果寫到標準輸出。
選項:
-c, -C, --complement 首先補足SET1
-d, --delete 刪除匹配SET1 的內容,並不做替換
-s, --squeeze-repeats 若是匹配於SET1 的字符在輸入序列中存在連續的重複,在替換時會被統一縮爲一個字符的長度
-t, --truncate-set1 先將SET1 的長度截爲和SET2 相等
--help 顯示此幫助信息並退出
--version 顯示版本信息並退出
二、SET字符串
SET 是一組字符串,通常均可按照字面含義理解。解析序列以下:
\NNN
#八進制值爲NNN 的字符(1 至3 個數位)
\\
#反斜槓
\a
#終端鳴響
\b
#退格
\f
#換頁
\n
#換行
\r
#回車
\t
#水平製表符
\
v
#垂直製表符
字符1-字符2
#從字符1 到字符2 的升序遞增過程當中經歷的全部字符
[字符*]
#在SET2 中適用,指定字符會被連續複製直到吻合設置1 的長度
[字符*次數]
#對字符執行指定次數的複製,若次數以 0 開頭則被視爲八進制數
[:alnum:]
#全部的字母和數字
[:alpha:]
#全部的字母
[:blank:]
#全部呈水平排列的空白字符
[:cntrl:]
#全部的控制字符
[:digit:]
#全部的數字
[:graph:]
#全部的可打印字符,不包括空格
[:lower:]
#全部的小寫字母
[:print:]
#全部的可打印字符,包括空格
[:punct:]
#全部的標點字符
[:space:]
#全部呈水平或垂直排列的空白字符
[:upper:]
#全部的大寫字母
[:xdigit:]
#全部的十六進制數
[=字符=]
#全部和指定字符相等的字符
注意:
一、僅在SET1 和SET2 都給出,同時沒有-d 選項的時候纔會進行替換。
二、僅在替換時纔可能用到-t 選項。若是須要SET2 將被經過在末尾添加原來的末字符的方式補充到同SET1 等長。SET2 中多餘的字符將被省略。
三、只有[:lower:] 和[:upper:]以升序展開字符;在用於替換時的SET2 中以成對錶示大小寫轉換。
四、-s 做用於SET1,既不替換也不刪除,不然在替換或展開後使用SET2 縮減。
|
tr示例:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
一、將文件
file
中出現的
"abc"
替換爲
"xyz"
# cat file | tr "abc" "xyz" > new_file
【注意】這裏,凡是在
file
中出現的
"a"
字母,都替換成
"x"
字母,
"b"
字母替換爲
"y"
字母,
"c"
字母替換爲
"z"
字母。而不是將字符串
"abc"
替換爲字符串
"xyz"
。
二、使用
tr
命令「統一」字母大小寫
(小寫 --> 大寫)
# cat file | tr [a-z] [A-Z] > new_file
(大寫 --> 小寫)
# cat file | tr [A-Z] [a-z] > new_file
三、把文件中的數字0-9替換爲a-j
# cat file | tr [0-9] [a-j] > new_file
四、刪除文件
file
中出現的
"Snail"
字符
# cat file | tr -d "Snail" > new_file
【注意】這裏,凡是在
file
文件中出現的
'S'
,
'n'
,
'a'
,
'i'
,
'l'
字符都會被刪除!而不是牢牢刪除出現的"Snail」字符串。
五、刪除文件
file
中出現的換行
'\n'
、製表
'\t'
字符
# cat file | tr -d "\n\t" > new_file
不可見字符都得用轉義字符來表示的,這個都是統一的。
六、刪除「連續着的」重複字母,只保留第一個
# cat file | tr -s [a-zA-Z] > new_file
七、刪除空行
# cat file | tr -s "\n" > new_file
八、刪除Windows文件「形成」的
'^M'
字符
# cat file | tr -d "\r" > new_file
或者
# cat file | tr -s "\r" "\n" > new_file
【注意】這裏-s後面是兩個參數
"\r"
和
"\n"
,用後者替換前者
九、用空格符\040替換製表符\011
# cat file | tr -s "\011" "\040" > new_file
十、把路徑變量中的冒號
":"
,替換成換行符
"\n"
# echo $PATH | tr -s ":" "\n"
|
2.4. 插入子串
插入子串:就是在指定的位置插入子串,這個位置多是某個子串的位置,也多是從某個文件開頭算起的某個長度。經過上面的練習,咱們發現這二者之間 其實是相似的。
公式:插入子串=把"old子串"替換成"old子串+new子串"或者"new子串+old子串"
概要示例::下面在var字符串的空格以前或以後插入一個下劃線
// 用{}
$ var="get the length of me"
$ echo ${var/ /_ } #在指定字符串以前插入一個字符串
get_ the length of me
$ echo ${var// /_ }
get_ the_ length_ of_ me
$ echo ${var/ / _} #在指定字符串以後插入一個字符串
get _the length of me
$ echo ${var// / _}
get _the _length _of _me
// 其餘的還用演示麼?這裏主要介紹sed怎麼用來插入字符吧,由於它的標籤功能頗有趣
$ echo $var | sed -e 's/\( \)/_\1/' #\(和\)將不匹配到的字符串存放爲一個標籤,按匹配順序爲\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的標籤的順序是否是\1,\2....,看到沒?\2和\1掉換位置後,the和get的位置掉換了
$ echo $var | sed -e 's/\([a-z]*\) \([a-z]*\) /\2 \1 /g'
the get of length me
// sed還有專門的插入指令,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. 刪除子串
刪除子串:應該很簡單了吧,把子串替換成「空」(什麼都沒有)不就變成了刪除麼。仍是來簡單複習一下替換吧。
概要示例::把var字符串中全部的空格給刪除掉。
鼓勵: 這樣一替換不知道變成什麼單詞啦,誰認得呢?可是中文倒是連在一塊兒的,因此中文有多難,你想到了麼?原來你也是個語言天才,而英語並不可怕,你有學會它的 天賦,只要你有這個打算。
// 再用{}
$ echo ${var// /}
getthelengthofme
// 再用awk
$ echo $var | awk '{gsub(" ","",$0); printf("%s\n", $0);}'
// 再用sed
$ echo $var | sed 's/ //g'
getthelengthofme
// 還有更簡單的tr命令,tr也能夠把" "給刪除掉,看
$ echo $var | tr -d " "
getthelengthofme
若是要刪除掉第一個空格後面全部的字符串該怎麼辦呢?還記得{}的#和%用法麼?若是不記得,回到這一節的還頭開始複習吧。(實際上刪除子串和取子串何嘗 不是兩種互補的運算呢,刪除掉某些不想要的子串,也就同時取得另外那些想要的子串——這個世界就是一個「二元」的世界,很是有趣)
2.6. 子串比較
這個很簡單:還記得test命令的用法麼?man test。它能夠用來判斷兩個字符串是否相等的。另外,你發現了「字符串是否相等」和「字符串可否跟另一個字符串匹配"兩個問題之間的關係嗎?若是兩個 字符串徹底匹配,那麼這兩個字符串就相等了。因此呢,上面用到的字符串匹配方法,也一樣能夠用到這裏。
2.7. 子串排序
差點忘記這個重要的內容了,子串排序但是常常用到的,常見的有按字母序、數字序等正序或反序排列。sort命令能夠用來作這個工做,它和其餘行處理 命令同樣,是按行操做的,另外,它相似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
2.7. 子串進制轉換
若是字母和數字字符用來計數,那麼就存在進制轉換的問題。在數值計算一節的回覆資料裏,咱們已經介紹了bc命令,這裏再簡單的複習一下。
$ echo "ibase=10;obase=16;10" | bc
A
說明:ibase指定輸入進制,obase指出輸出進制,這樣經過調整ibase和obase,你想怎麼轉就怎麼轉啦!
2.7. 子串編碼轉換
什麼是字符編碼?這個就不用介紹了吧,看過那些亂七八糟顯示的網頁麼?大可能是由於瀏覽器顯示時的」編碼「和網頁實際採用的」編碼「不一致致使的。字 符編碼一般是指把一序列」可打印「字符轉換成二進制表示,而字符解碼呢則是執行相反的過程,若是這兩個過程不匹配,則出現了所謂的」亂碼「。
爲了解決」亂碼「問題呢?就須要進行編碼轉換。在linux下,咱們可使用iconv這個工具來進行相關操做。這樣的狀況常常在不一樣的操做系統之 間移動文件,不一樣的編輯器之間交換文件的時候遇到,目前在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
你好
說明:個人終端默認編碼是utf8,因此結果如上。
3. 字符串操做範例
實際上,在用Bash編程時,大部分時間都是在處理字符串,所以把這一節熟練掌握很是重要。
3.1 處理一個很是有意義的字符串:URL地址
範例演示:處理URL地址
URL 地址(URL(Uniform Resoure Locator:統一資源定位器)是WWW頁的地址)幾乎是咱們平常生活的玩伴,咱們已經到了沒法離開它的地步啦,對它的操做不少,包括判斷URL地址的 有效性,截取地址的各個部分(服務器類型、服務器地址、端口、路徑等)並對各個部分進行進一步的操做。
下面咱們來具體處理這個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\./ -]*"
// 截取服務器類型
$ 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
// 截取文件類型(擴展名)
$ echo $url | sed -e 's/.*[0-9].\(.*\)/\1/g'
tar.gz
有了上面的知識,咱們就能夠很是容易地進行這些工做啦:修改某個文件的文件名,好比調整它的編碼,下載某個網頁裏頭的全部pdf文檔等。這些就做爲練習自 己作吧,若是遇到問題,能夠在回帖交流。相應地能夠參考這個例子:
[1] 用腳本下載某個網頁中的英文原著(pdf文檔)
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1228.html
3.2 處理格式化的文本:/etc/passwd
平時作工做,大多數時候處理的都是一些「格式化」的文本,好比相似/etc/passwd這樣的有固定行和列的文本,也有相似tree命令輸出的那 種具備樹形結構的文本,固然還有其餘具備特定結構的文本。
關於樹狀結構的文本的處理,能夠考慮看看這兩個例子:
[1] 用AWK轉換樹形數據成關係表
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1260.html
[2] 用Graphviz進行可視化操做──繪製函數調用關係圖
http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1425.html
實際上,只要把握好特性結構的一些特色,並根據具體的應用場合,處理起來就不會困難。
下面咱們來介紹具體有固定行和列的文本的操做,以/etc/passwd文件爲例。關於這個文件的幫忙和用戶,請經過man 5 passwd查看。下面咱們對這個文件以及相關的文件進行一些有意義的操做。
// 選取/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命令用來鏈接兩個文件,有點相似於數據庫的兩個表的鏈接。-t指定分割符,"-1 4 -2 3"指定按照第一個文件的第4列和第二個文件的第3列,即組ID進行鏈接,"-o 1.1,2.1"表示僅僅輸出第一個文件的第一列和第二個文件的第一列,這樣就獲得了咱們要的結果,不過,惋惜的是,這個結果並不許確,再進行下面的操 做,你就會發現:
$ 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
// 能夠看到這個結果纔是正確的,因此之後使用join千萬要注意這個問題,不然採起更保守的作法彷佛更能保證正確性,更多關於文件鏈接的討論見參考資料 [14]
上面涉及到了處理某格式化行中的指定列,包括截取(如SQL的select用法),鏈接(如SQL的join用法),排序(如SQL的order by用法),均可以經過指定分割符來拆分某個格式化的行,另外,「截取」的作法還有不少,不光是cut,awk,甚至經過IFS指定分割符的read命令 也能夠作到,例如:
$ IFS=":"; cat /etc/group | while read C1 C2 C3 C4; do echo $C1 $C3; done
所以,熟悉這些用法,咱們的工做將變得很是靈活有趣。
到這裏,須要作一個簡單的練習,如何把按照列對應的用戶名和用戶ID轉換成按照行對應的,即把相似下面的數據:
$ cat /etc/passwd | cut -d":" -f1,3 --output-delimiter=" "
root 0
bin 1
daemon 2
轉換成:
$ cat a
root bin daemon
0 1 2
並轉換回去,有什麼辦法呢?記得諸如tr,paste,split等命令均可以使用。
參考方法:
*正轉換:先截取用戶名一列存入文件user,再截取用戶ID存入id,再把兩個文件用paste -s命令連在一塊兒,這樣就完成了正轉換。
*逆轉換:先把正轉換獲得的結果用split -1拆分紅兩個文件,再把兩個拆分後的文件用tr把分割符"\t"替換成"\n",只有用paste命令把兩個文件連在一塊兒,這樣就完成了逆轉換。
在作shell批處理程序時候,常常會涉及到字符串相關操做。有不少命令語句,如:awk,sed均可以作字符串各類操做。 其實shell內置一系列操做符號,能夠達到相似效果,你們知道,使用內部操做符會省略啓動外部程序等時間,所以速度會很是的快。
1、判斷讀取字符串值
表達式 | 含義 |
---|---|
${var} | 變量var的值, 與$var相同 |
${var-DEFAULT} | 若是var沒有被聲明, 那麼就以$DEFAULT做爲其值 * |
${var:-DEFAULT} | 若是var沒有被聲明, 或者其值爲空, 那麼就以$DEFAULT做爲其值 * |
${var=DEFAULT} | 若是var沒有被聲明, 那麼就以$DEFAULT做爲其值 * |
${var:=DEFAULT} | 若是var沒有被聲明, 或者其值爲空, 那麼就以$DEFAULT做爲其值 * |
${var+OTHER} | 若是var聲明瞭, 那麼其值就是$OTHER, 不然就爲null字符串 |
${var:+OTHER} | 若是var被設置了, 那麼其值就是$OTHER, 不然就爲null字符串 |
${var?ERR_MSG} | 若是var沒被聲明, 那麼就打印$ERR_MSG * |
${var:?ERR_MSG} | 若是var沒被設置, 那麼就打印$ERR_MSG * |
${!varprefix*} | 匹配以前全部以varprefix開頭進行聲明的變量 |
${!varprefix@} | 匹配以前全部以varprefix開頭進行聲明的變量 |
加入了「*」 的意思是: 若是變量var已經被設置的話, 那麼其值就是$var.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[a@localhost ~]$
echo
${abc-
'ok'
}
ok
[a@localhost ~]$
echo
$abc
[a@localhost ~]$
echo
${abc=
'ok'
}
ok
[a@localhost ~]$
echo
$abc
ok
若是abc 沒有聲明「=" 還會給abc賦值。
[a@localhost ~]$ var1=11;var2=12;var3=
[a@localhost ~]$
echo
${!
v
@}
var1 var2 var3
[a@localhost ~]$
echo
${!
v
*}
var1 var2 var3
${!varprefix*}與${!varprefix@}類似,能夠經過變量名前綴字符,搜索已經定義的變量,不管是否爲空值。
|
表達式 | 含義 |
---|---|
${#string} | $string的長度 |
${string:position} | 在$string中, 從位置$position開始提取子串 |
${string:position:length} | 在$string中, 從位置$position開始提取長度爲$length的子串 |
${string#substring} | 從變量$string的開頭, 刪除最短匹配$substring的子串 |
${string##substring} | 從變量$string的開頭, 刪除最長匹配$substring的子串 |
${string%substring} | 從變量$string的結尾, 刪除最短匹配$substring的子串 |
${string%%substring} | 從變量$string的結尾, 刪除最長匹配$substring的子串 |
${string/substring/replacement} | 使用$replacement, 來代替第一個匹配的$substring |
${string//substring/replacement} | 使用$replacement, 代替全部匹配的$substring |
${string/#substring/replacement} | 若是$string的前綴匹配$substring, 那麼就用$replacement來代替匹配到的$substring |
${string/%substring/replacement} | 若是$string的後綴匹配$substring, 那麼就用$replacement來代替匹配到的$substring |
說明:"* $substring」能夠是一個正則表達式.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
1.長度
[a@localhost ~]$
test
=
'I love china'
[a@localhost ~]$
echo
${
#test}
12
${
#變量名}獲得字符串長度
2.截取字串
[a@localhost ~]$
test
=
'I love china'
[a@localhost ~]$
echo
${
test
:5}
e china
[a@localhost ~]$
echo
${
test
:5:10}
e china
${變量名:起始:長度}獲得子字符串
3.字符串刪除
[a@localhost ~]$
test
=
'c:/windows/boot.ini'
[a@localhost ~]$
echo
${
test
#/}
c:
/windows/boot
.ini
[a@localhost ~]$
echo
${
test
#*/}
windows
/boot
.ini
[a@localhost ~]$
echo
${
test
##*/}
boot.ini
[a@localhost ~]$
echo
${
test
%/*}
c:
/windows
[a@localhost ~]$
echo
${
test
%%/*}
${變量名
#substring正則表達式}從字符串開頭開始配備substring,刪除匹配上的表達式。
${變量名%substring正則表達式}從字符串結尾開始配備substring,刪除匹配上的表達式。
注意:${
test
##*/},${test%/*} 分別是獲得文件名,或者目錄地址最簡單方法。
4.字符串替換
[a@localhost ~]$
test
=
'c:/windows/boot.ini'
[a@localhost ~]$
echo
${
test
/\
//
\\}
c:\windows
/boot
.ini
[a@localhost ~]$
echo
${
test
//
\
//
\\}
c:\windows\boot.ini
${變量/查找/替換值} 一個「/」表示替換第一個,」
//
」表示替換全部,當查找中出現了:」/」請加轉義符」\/」表示。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
在shell中,經過
awk
,
sed
,
expr
等均可以實現,字符串上述操做。下面咱們進行性能比較。
[a@localhost ~]$
test
=
'c:/windows/boot.ini'
[a@localhost ~]$
time
for
i
in
$(
seq
10000);
do
a=${
#test};done;
real 0m0.173s
user 0m0.139s
sys 0m0.004s
[a@localhost ~]$
time
for
i
in
$(
seq
10000);
do
a=$(
expr
length $
test
);
done
;
real 0m9.734s
user 0m1.628s
速度相差上百倍,調用外部命令處理,與內置操做符性能相差很是大。在shell編程中,儘可能用內置操做符或者函數完成。使用
awk
,
sed
相似會出現這樣結果。
|