鍍金池/ 教程/ Linux/ 文本處理
進(jìn)程管理工具
objdump 二進(jìn)制文件分析
scp 跨機(jī)遠(yuǎn)程拷貝
crontab 定時(shí)任務(wù)
readelf elf文件格式分析
pstack 跟蹤進(jìn)程棧
系統(tǒng)管理及IPC資源管理
vmstat 監(jiān)視內(nèi)存使用情況
strace 跟蹤進(jìn)程中的系統(tǒng)調(diào)用
sar 找出系統(tǒng)瓶頸的利器
ipcs 查詢進(jìn)程間通信狀態(tài)
ps 進(jìn)程查看器
性能優(yōu)化
wget 文件下載
top linux下的任務(wù)管理器
磁盤管理
size 查看程序內(nèi)存映像大小
free 查詢可用內(nèi)存
文件及目錄管理
iostat 監(jiān)視I/O子系統(tǒng)
性能監(jiān)控
程序構(gòu)建
學(xué)會(huì)使用命令幫助
gdb 調(diào)試?yán)?/span>
網(wǎng)絡(luò)工具
nm 目標(biāo)文件格式分析
lsof 一切皆文件
用戶管理工具
程序調(diào)試
ldd 查看程序依賴庫
文本處理

文本處理

本節(jié)將介紹Linux下使用Shell處理文本時(shí)最常用的工具: find、grep、xargs、sort、uniq、tr、cut、paste、wc、sed、awk; 提供的例子和參數(shù)都是常用的; 我對(duì)shell腳本使用的原則是命令單行書寫,盡量不要超過2行; 如果有更為復(fù)雜的任務(wù)需求,還是考慮python吧;

find 文件查找

查找txt和pdf文件

find . \( -name "*.txt" -o -name "*.pdf" \) -print

正則方式查找.txt和pdf

find . -regex  ".*\(\.txt|\.pdf\)$"

-iregex: 忽略大小寫的正則

否定參數(shù) ,查找所有非txt文本

find . ! -name "*.txt" -print

指定搜索深度,打印出當(dāng)前目錄的文件(深度為1)

find . -maxdepth 1 -type f

定制搜索

  • 按類型搜索
    find . -type d -print  //只列出所有目錄
-type f 文件 / l 符號(hào)鏈接 / d  目錄 

find支持的文件檢索類型可以區(qū)分普通文件和符號(hào)鏈接、目錄等,但是二進(jìn)制文件和文本文件無法直接通過find的類型區(qū)分出來;

file命令可以檢查文件具體類型(二進(jìn)制或文本)

$file redis-cli  # 二進(jìn)制文件
redis-cli: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
$file redis.pid  # 文本文件
redis.pid: ASCII text

所以,可以用以下命令組合來實(shí)現(xiàn)查找本地目錄下的所有二進(jìn)制文件

ls -lrt | awk '{print $9}'|xargs file|grep  ELF| awk '{print $1}'|tr -d ':'
  • 按時(shí)間搜索
    • -atime 訪問時(shí)間 (單位是天,分鐘單位則是-amin,以下類似)
    • -mtime 修改時(shí)間 (內(nèi)容被修改)
    • -ctime 變化時(shí)間 (元數(shù)據(jù)或權(quán)限變化)

最近第7天被訪問過的所有文件

find . -atime 7 -type f -print

最近7天內(nèi)被訪問過的所有文件

find . -atime -7 -type f -print

查詢7天前被訪問過的所有文件

find . -atime +7 type f -print
  • 按大小搜索 w字 k M G尋找大于2k的文件
    find . -type f -size +2k

按權(quán)限查找

find . -type f -perm 644 -print //找具有可執(zhí)行權(quán)限的所有文件

按用戶查找

find . -type f -user weber -print// 找用戶weber所擁有的文件

找到后的后續(xù)動(dòng)作

刪除當(dāng)前目錄下所有的swp文件

find . -type f -name "*.swp" -delete

另一種語法

find . type f -name "*.swp" | xargs rm
  • 執(zhí)行動(dòng)作(強(qiáng)大的exec)

將當(dāng)前目錄下的所有權(quán)變更為weber

find . -type f -user root -exec chown weber {} \; 

注:{}是一個(gè)特殊的字符串,對(duì)于每一個(gè)匹配的文件,{}會(huì)被替換成相應(yīng)的文件名;

將找到的文件全都copy到另一個(gè)目錄

find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \;
  • 結(jié)合多個(gè)命令

如果需要后續(xù)執(zhí)行多個(gè)命令,可以將多個(gè)命令寫成一個(gè)腳本。然后 -exec 調(diào)用時(shí)執(zhí)行腳本即可

-exec ./commands.sh {} \;

-print的定界符

默認(rèn)使用'\\n'作為文件的定界符;

-print0 使用'\\0'作為文件的定界符,這樣就可以搜索包含空格的文件;

grep 文本搜索

grep match_patten file // 默認(rèn)訪問匹配行

常用參數(shù)

  • -o 只輸出匹配的文本行 VS -v 只輸出沒有匹配的文本行
  • -c 統(tǒng)計(jì)文件中包含文本的次數(shù) grep -c "text" filename
  • -n 打印匹配的行號(hào)
  • -i 搜索時(shí)忽略大小寫
  • -l 只打印文件名

在多級(jí)目錄中對(duì)文本遞歸搜索(程序員搜代碼的最愛)

grep "class" . -R -n

匹配多個(gè)模式

grep -e "class" -e "vitural" file

grep輸出以\0作為結(jié)尾符的文件名(-z)

grep "test" file* -lZ| xargs -0 rm

綜合應(yīng)用:將日志中的所有帶where條件的sql查找查找出來

cat LOG.* | tr a-z A-Z | grep "FROM " | grep "WHERE" > b

查找中文示例:工程目錄中utf-8格式和gb2312格式兩種文件,要查找字的是中文;

  1. 查找到它的utf-8編碼和gb2312編碼分別是E4B8ADE69687和D6D0CEC4
  2. 查詢

      grep:grep -rnP "\xE4\xB8\xAD\xE6\x96\x87|\xD6\xD0\xCE\xC4" *即可

漢字編碼查詢:http://bm.kdd.cc/

xargs 命令行參數(shù)轉(zhuǎn)換

xargs 能夠?qū)⑤斎霐?shù)據(jù)轉(zhuǎn)化為特定命令的命令行參數(shù);這樣,可以配合很多命令來組合使用。比如grep,比如find;

  • 將多行輸出轉(zhuǎn)化為單行輸出
    cat file.txt| xargs

\n 是多行文本間的定界符

  • 將單行轉(zhuǎn)化為多行輸出
    cat single.txt | xargs -n 3

-n:指定每行顯示的字段數(shù)

xargs參數(shù)說明

  • -d 定義定界符 (默認(rèn)為空格 多行的定界符為 \n)
  • -n 指定輸出為多行
  • -I {} 指定替換字符串,這個(gè)字符串在xargs擴(kuò)展時(shí)會(huì)被替換掉,用于待執(zhí)行的命令需要多個(gè)參數(shù)時(shí)
  • -0:指定\0為輸入定界符

示例

cat file.txt | xargs -I {} ./command.sh -p {} -1

#統(tǒng)計(jì)程序行數(shù)
find source_dir/ -type f -name "*.cpp" -print0 |xargs -0 wc -l

#redis通過string存儲(chǔ)數(shù)據(jù),通過set存儲(chǔ)索引,需要通過索引來查詢出所有的值:
./redis-cli smembers $1  | awk '{print $1}'|xargs -I {} ./redis-cli get {}

sort 排序

字段說明

  • -n 按數(shù)字進(jìn)行排序 VS -d 按字典序進(jìn)行排序
  • -r 逆序排序
  • -k N 指定按第N列排序

示例

sort -nrk 1 data.txt
sort -bd data // 忽略像空格之類的前導(dǎo)空白字符

uniq 消除重復(fù)行

  • 消除重復(fù)行
    sort unsort.txt | uniq
  • 統(tǒng)計(jì)各行在文件中出現(xiàn)的次數(shù)
    sort unsort.txt | uniq -c
  • 找出重復(fù)行
    sort unsort.txt | uniq -d

可指定每行中需要比較的重復(fù)內(nèi)容:-s 開始位置 -w 比較字符數(shù)

用tr進(jìn)行轉(zhuǎn)換

  • 通用用法
    echo 12345 | tr '0-9' '9876543210' //加解密轉(zhuǎn)換,替換對(duì)應(yīng)字符
    cat text| tr '\t' ' '  //制表符轉(zhuǎn)空格
  • tr刪除字符
    cat file | tr -d '0-9' // 刪除所有數(shù)字
  • c 求補(bǔ)集
    cat file | tr -c '0-9' //獲取文件中所有數(shù)字
    cat file | tr -d -c '0-9 \n'  //刪除非數(shù)字?jǐn)?shù)據(jù)
  • tr壓縮字符 tr -s 壓縮文本中出現(xiàn)的重復(fù)字符;最常用于壓縮多余的空格
    cat file | tr -s ' '
  • 字符類

tr中可用各種字符類:

  • alnum:字母和數(shù)字
  • alpha:字母
  • digit:數(shù)字
  • space:空白字符
  • lower:小寫
  • upper:大寫
  • cntrl:控制(非可打印)字符
  • print:可打印字符

使用方法:tr [:class:] [:class:]

     tr '[:lower:]' '[:upper:]'

cut 按列切分文本

  • 截取文件的第2列和第4列
    cut -f2,4 filename
  • 去文件除第3列的所有列
    cut -f3 --complement filename
  • -d 指定定界符
    cat -f2 -d";" filename
  • cut 取的范圍
    • N- 第N個(gè)字段到結(jié)尾
    • -M 第1個(gè)字段為M
    • N-M N到M個(gè)字段
  • cut 取的單位
    • -b 以字節(jié)為單位
    • -c 以字符為單位
    • -f 以字段為單位(使用定界符)

示例

cut -c1-5 file //打印第一到5個(gè)字符
cut -c-2 file  //打印前2個(gè)字符

截取文本的第5到第7列

$echo string | cut -c5-7

paste 按列拼接文本

將兩個(gè)文本按列拼接到一起;

cat file1
1
2

cat file2
colin
book

paste file1 file2
1 colin
2 book

默認(rèn)的定界符是制表符,可以用-d指明定界符

paste file1 file2 -d ","
1,colin
2,book

wc 統(tǒng)計(jì)行和字符的工具

$wc -l file // 統(tǒng)計(jì)行數(shù)

$wc -w file // 統(tǒng)計(jì)單詞數(shù)

$wc -c file // 統(tǒng)計(jì)字符數(shù)

sed 文本替換利器

  • 首處替換
    sed 's/text/replace_text/' file   //替換每一行的第一處匹配的text
  • 全局替換
    sed 's/text/replace_text/g' file

默認(rèn)替換后,輸出替換后的內(nèi)容,如果需要直接替換原文件,使用-i

    sed -i 's/text/repalce_text/g' file
  • 移除空白行
    sed '/^$/d' file
  • 變量轉(zhuǎn)換 已匹配的字符串通過標(biāo)記&來引用.
    echo this is en example | sed 's/\w+/[&]/g'
    $>[this]  [is] [en] [example]
  • 子串匹配標(biāo)記 第一個(gè)匹配的括號(hào)內(nèi)容使用標(biāo)記 \1 來引用
    sed 's/hello\([0-9]\)/\1/'
  • 雙引號(hào)求值

sed通常用單引號(hào)來引用;也可使用雙引號(hào),使用雙引號(hào)后,雙引號(hào)會(huì)對(duì)表達(dá)式求值

    sed 's/$var/HLLOE/'

當(dāng)使用雙引號(hào)時(shí),我們可以在sed樣式和替換字符串中指定變量;

eg:
p=patten
r=replaced
echo "line con a patten" | sed "s/$p/$r/g"
$>line con a replaced
  • 其它示例 字符串插入字符:將文本中每行內(nèi)容(ABCDEF) 轉(zhuǎn)換為 ABC/DEF
    sed 's/^.\{3\}/&\//g' file

awk 數(shù)據(jù)流處理工具

  • awk腳本結(jié)構(gòu)
    awk ' BEGIN{ statements } statements2 END{ statements } '
  • 工作方式 1.執(zhí)行begin中語句塊;

2.從文件或stdin中讀入一行,然后執(zhí)行statements2,重復(fù)這個(gè)過程,直到文件全部被讀取完畢;

3.執(zhí)行end語句塊;

print 打印當(dāng)前行

  • 使用不帶參數(shù)的print時(shí),會(huì)打印當(dāng)前行
    echo -e "line1\nline2" | awk 'BEGIN{print "start"} {print } END{ print "End" }'
  • print 以逗號(hào)分割時(shí),參數(shù)以空格定界;
    echo | awk ' {var1 = "v1" ; var2 = "V2"; var3="v3"; \
    print var1, var2 , var3; }'
    $>v1 V2 v3
  • 使用-拼接符的方式(""作為拼接符);
    echo | awk ' {var1 = "v1" ; var2 = "V2"; var3="v3"; \
    print var1"-"var2"-"var3; }'
    $>v1-V2-v3

特殊變量: NR NF $0 $1 $2

NR:表示記錄數(shù)量,在執(zhí)行過程中對(duì)應(yīng)當(dāng)前行號(hào);

NF:表示字段數(shù)量,在執(zhí)行過程總對(duì)應(yīng)當(dāng)前行的字段數(shù);

$0:這個(gè)變量包含執(zhí)行過程中當(dāng)前行的文本內(nèi)容;

$1:第一個(gè)字段的文本內(nèi)容;

$2:第二個(gè)字段的文本內(nèi)容;

    echo -e "line1 f2 f3\n line2 \n line 3" | awk '{print NR":"$0"-"$1"-"$2}'
  • 打印每一行的第二和第三個(gè)字段
    awk '{print $2, $3}' file
  • 統(tǒng)計(jì)文件的行數(shù)
    awk ' END {print NR}' file
  • 累加每一行的第一個(gè)字段
    echo -e "1\n 2\n 3\n 4\n" | awk 'BEGIN{num = 0 ;
    print "begin";} {sum += $1;} END {print "=="; print sum }'

傳遞外部變量

    var=1000
    echo | awk '{print vara}' vara=$var #  輸入來自stdin
    awk '{print vara}' vara=$var file # 輸入來自文件

用樣式對(duì)awk處理的行進(jìn)行過濾

awk 'NR < 5' #行號(hào)小于5
awk 'NR==1,NR==4 {print}' file #行號(hào)等于1和4的打印出來
awk '/linux/' #包含linux文本的行(可以用正則表達(dá)式來指定,超級(jí)強(qiáng)大)
awk '!/linux/' #不包含linux文本的行

設(shè)置定界符

使用-F來設(shè)置定界符(默認(rèn)為空格)

    awk -F: '{print $NF}' /etc/passwd

讀取命令輸出

使用getline,將外部shell命令的輸出讀入到變量cmdout中

    echo | awk '{"grep root /etc/passwd" | getline cmdout; print cmdout }'

在awk中使用循環(huán)

for(i=0;i<10;i++){print $i;}
for(i in array){print array[i];}

eg:以下字符串,打印出其中的時(shí)間串

2015_04_02 20:20:08: mysqli connect failed, please check connect info
$echo '2015_04_02 20:20:08: mysqli connect failed, please check connect info'|awk -F ":" '{ for(i=1;i<=;i++) printf("%s:",$i)}'
>2015_04_02 20:20:08:  # 這種方式會(huì)將最后一個(gè)冒號(hào)打印出來
$echo '2015_04_02 20:20:08: mysqli connect failed, please check connect info'|awk -F':' '{print $1 ":" $2 ":" $3; }'
>2015_04_02 20:20:08   # 這種方式滿足需求

而如果需要將后面的部分也打印出來(時(shí)間部分和后文分開打印)

$echo '2015_04_02 20:20:08: mysqli connect failed, please check connect info'|awk -F':' '{print $1 ":" $2 ":" $3; print $4;}'
>2015_04_02 20:20:08
>mysqli connect failed, please check connect info

以逆序的形式打印行:(tac命令的實(shí)現(xiàn))

seq 9| \
awk '{lifo[NR] = $0; lno=NR} \
END{ for(;lno>-1;lno--){print lifo[lno];}
} '

awk結(jié)合grep找到指定的服務(wù),然后將其kill掉

ps -fe| grep msv8 | grep -v MFORWARD | awk '{print $2}' | xargs kill -9;

awk實(shí)現(xiàn)head、tail命令

  • head
    awk 'NR<=10{print}' filename
  • tail
    awk '{buffer[NR%10] = $0;} END{for(i=0;i<11;i++){ \
    print buffer[i %10]} } ' filename

打印指定列

  • awk方式實(shí)現(xiàn)
    ls -lrt | awk '{print $6}'
  • cut方式實(shí)現(xiàn)
    ls -lrt | cut -f6

打印指定文本區(qū)域

  • 確定行號(hào)
    seq 100| awk 'NR==4,NR==6{print}'
  • 確定文本 打印處于start_pattern 和end_pattern之間的文本
    awk '/start_pattern/, /end_pattern/' filename

示例

seq 100 | awk '/13/,/15/'
cat /etc/passwd| awk '/mai.*mail/,/news.*news/'

awk常用內(nèi)建函數(shù)

index(string,search_string):返回search_string在string中出現(xiàn)的位置

sub(regex,replacement_str,string):將正則匹配到的第一處內(nèi)容替換為replacement_str;

match(regex,string):檢查正則表達(dá)式是否能夠匹配字符串;

length(string):返回字符串長度

    echo | awk '{"grep root /etc/passwd" | getline cmdout; print length(cmdout) }'

printf 類似c語言中的printf,對(duì)輸出進(jìn)行格式化

seq 10 | awk '{printf "->%4s\n", $1}'

迭代文件中的行、單詞和字符

1. 迭代文件中的每一行

  • while 循環(huán)法
    while read line;
    do
    echo $line;
    done < file.txt

    改成子shell:
    cat file.txt | (while read line;do echo $line;done)
  • awk法
    cat file.txt| awk '{print}'

2.迭代一行中的每一個(gè)單詞

    for word in $line;
    do
    echo $word;
    done

3. 迭代每一個(gè)字符

${string:start_pos:num_of_chars}:從字符串中提取一個(gè)字符;(bash文本切片)

${#word}:返回變量word的長度

    for((i=0;i<${#word};i++))
    do
    echo ${word:i:1);
    done

以ASCII字符顯示文件

    $od -c filename
上一篇:wget 文件下載下一篇:性能優(yōu)化