作者:LogM
本文原載於 https://segmentfault.com/u/logm/articles ,不允許轉載~
0. 關於 Linux 命令的正則表達式
awk
、sed
、grep
使用的是不同標準的正則表達式,而且與 C++
、Python
、Java
中的正則表達式標準還不一樣,真的蛋疼,詳見 正則表達式派別綜述。
1. find
文件查找
# 查找txt文件
# -iname:忽略大小寫
find . -name "*.txt"
find . -iname "*.txt"
# 正則表達式查找.txt和.cpp文件,注意特殊符號用`\`轉義
# -iregex:忽略大小寫
find . -regex ".*\.\(txt\|cpp\)$"
find . -iregex ".*\.\(txt\|cpp\)$"
# 使用`!`進行否定,查找非.txt或.cpp的所有文件
find . ! -regex ".*\.\(txt\|cpp\)$"
# 查找指定深度和指定類型:f爲文件,d爲目錄,l爲符號連接
find . -maxdepth 3 -type f
# 查找後進行指定操作,`-ok`逐文件提示是否進行操作,`-exec`無提示,注意結尾的`;`
find . -type f -name "*.txt" -ok cat {} \;
find . -type f -name "*.txt" -exec cat {} \;
2. grep
文本搜索
# 在文件中查找"match_pattern",允許多個文件,支持正則表達式
grep "match_pattern" file_1 file_2 file_3
# grep 使用的正則表達式有點特殊,我自己會使用`-P`來打開"PCRE正則兼容"
grep -P "match_pattern" file_1 file_2 file_3
# 只打印匹配到的文件名
grep -l "match_pattern" file_1 file_2 file_3
# 忽略大小寫
grep -i "match_pattern" file_name
# 輸出除"match_pattern"的其他行
grep -v "match_pattern" file_name
# 輸出的結果中,對匹配的區域進行高亮
grep "match_pattern" file_name --color=auto
# 只輸出匹配"match_pattern"的區域,而非一行
grep -o "match_pattern" file_name
# 每個輸出的前面帶上這個區域在原文件中的位置(第一個字符爲0,第二個字符爲1,依次類推),一般`-b``-o`連用
grep -b -o "match_pattern" file_name
# 每行輸出的前面帶上這行在原文件中的行號
grep -n "match_pattern" file_name
# 統計文件中包含文本的行數
grep -c "match_pattern" file_name
# 在目錄下遞歸查找,`-r`和`-R`效果相同
grep -r "match_pattern" path
grep -R "match_pattern" path
# `-e`允許多個"match_pattern"
grep -e ".*\.html" -e ".*\.php" file_name
# `-E`使用正則表達式的寫法有所改變,等同於egrep,貌似是`|`和`&`不再需要`\`轉義且`*`表示任意數量的任意字符
grep -E "*\.php|*\.html" file_name --color=auto
# 等同於
grep ".*\.html\|.*\.php" file_name
3. xargs
命令行參數轉換
xargs 能夠將輸入數據轉化爲特定命令的命令行參數;這樣,可以配合很多命令來組合使用。比如grep,比如find。
# 將多行輸出轉化爲單行輸出(`\n`是多行文本間的定界符)
cat file.txt| xargs
# 將單行轉化爲多行輸出(`-n`指定每行顯示的字段數)
cat single.txt | xargs -n 3
# xargs參數說明:
# -d 定義定界符 (默認爲空格 多行的定界符爲 \n)
# -n 指定輸出爲多行
# -I {} 指定替換字符串,這個字符串在xargs擴展時會被替換掉,用於待執行的命令需要多個參數時
# 複製所有圖片文件到 /data/images 目錄下
ls *.jpg | xargs -n1 -I {} cp {} /data/images
# 打印目錄下所有 .cpp 的文件的行數
find source_dir/ -type f -name "*.cpp" -print0 |xargs -0 wc -l
4. sort
排序
# -n 按數字進行排序 VS -d 按字典序進行排序
# -r 逆序排序
# -k N 指定按第N列排序
# -t 指定分割符
sort -nrk 1 data.txt
sort -bd data # 忽略像空格之類的前導空白字符
# 對於指定分割符爲特殊字符時需要注意
sort -t '\t' -k3 a.txt
# 上述命令報錯:sort: multi-character tab `\t'
# 正確寫法:
sort -t $'\t' -k3 a.txt
5. uniq
消除重複行
# 使用`uniq`前,必須先使用`sort`
sort unsort.txt | uniq # 行去重後的結果
sort unsort.txt | uniq -c # 行前打印該行重複次數
sort unsort.txt | uniq -d # 只打印出現重複的行
6. tr
替換或刪除字符
echo "HELLO WORLD" | tr 'A-Z' 'a-z' # 大寫字母轉小寫
cat text| tr '\t' ' ' # 製表符轉空格
# -d 刪除
cat file | tr -d '0-9' # 刪除所有的數字字符
# -c 求補集
cat file | tr -c '0-9' '?' # 把所有非數字的字符替換爲'?'
cat file | tr -d -c '0-9 \n' # 刪除所有非數字的字符,注意換行和空格的保留
# -s 壓縮文本中出現的重複字符;最常用於壓縮多餘的空格
cat file | tr -s ' ' # 刪除重複的空格
# 字符類
# tr中可用各種字符類:
# alnum:字母和數字
# alpha:字母
# digit:數字
# space:空白字符
# lower:小寫
# upper:大寫
# cntrl:控制(非可打印)字符
# print:可打印字符
# 使用方法:tr [:class:] [:class:]
tr '[:lower:]' '[:upper:]' # 大小寫轉換也可以這麼寫
7. cut
按列切分文本
# cut從每一行切割字符串,把指定列輸出
# -b:以字節爲單位,顯示每行第n個字節
# -c:以字符爲單位,顯示每行第n個字符
# -f:以分隔符分割字段,顯示每行第n個字段的內容
# -d:指定字段的分隔符,默認的字段分隔符爲“TAB”
# --complement 求補,提取指定字段之外的列
# cut 取的範圍:
# N- 第N個字段到結尾
# -M 第1個字段爲M
# N-M N到M個字段
cut -d";" -f2,4 filename # 提取文件的第2列和第4列,`;`分隔
cut -d";" -f3 --complement filename # 提取文件除第3列外的所有列:
cut -c1-5 file # 打印第1到5個字符
8. paste
按列拼接文本
# 將兩個文本按列拼接到一起
paste file1 file2 # 默認在列方向上合併
paste -s file1 file2 # 在行方向上合併
paste file1 file2 -d “,” # 指定合併後的字段分隔符
9. wc
統計行和字符的工具
wc -l file # 統計行數
wc -w file # 統計單詞數
wc -c file # 統計字符數
10. sed
文本替換利器
# s是sed命令,表示替換字符
# g是sed替換標記,表示全部替換
# 首處替換
seg 's/text/replace_text/' file # 替換每一行的第一處匹配的text
# 全局替換
seg 's/text/replace_text/g' file
# -i 直接修改源文件
seg -i 's/text/repalce_text/g' file
# 移除空白行:
# d是sed命令,表示刪除匹配的行
sed '/^$/d' file
# 變量轉換,已匹配的字符串通過標記&來引用
echo this is en example | seg 's/\w+/[&]/g'$
# 輸出:[this] [is] [en] [example]
# 子串匹配標記
# 第一個匹配的括號內容使用標記 \1 來引用
sed 's/hello\([0-9]\)/\1/'
# 雙引號求值
# sed通常用單引號來引用;也可使用雙引號,使用雙引號後,雙引號會對表達式求值:
sed 's/$var/HLLOE/'
# 當使用雙引號時,我們可以在sed樣式和替換字符串中指定變量;
eg:p=patten
r=replaced
echo "line con a patten" | sed "s/$p/$r/g"$>line con a replaced
# 其它示例
# 字符串插入字符:將文本中每行內容(PEKSHA) 轉換爲 PEK/SHA
sed 's/^.\{3\}/&\//g' file
11. awk
數據流處理工具
# awk腳本結構
awk 'BEGIN{ statements } statements2 END{ statements } '
# 工作方式:
# 執行begin中語句塊;
# 從文件或stdin中讀入一行,然後執行statements2,重複這個過程,直到文件全部被讀取完畢;
# 執行end語句塊;
# print 打印當前行
# 使用不帶參數的print時,會打印當前行;
echo -e "line1\nline2" | awk 'BEGIN{print "start"} {print } END{ print "End" }'
# print 以逗號分割時,參數以空格定界;
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:表示記錄數量,在執行過程中對應當前行號;
# NF:表示字段數量,在執行過程總對應當前行的字段數;
# $0:這個變量包含執行過程中當前行的文本內容;
# $1:第一個字段的文本內容;
# $2:第二個字段的文本內容;
echo -e "line1 f2 f3\n line2 \n line 3" | awk '{print NR":"1"-"$2}'
# 打印每一行的第二和第三個字段:
awk '{print $2, $3}' file
# 統計文件的行數:
awk ' END {print NR}' file
# 累加每一行的第一個字段:
echo -e "1\n 2\n 3\n 4\n" | awk 'BEGIN{sum = 0; print "begin";} {sum += $1;} END {print "=="; print sum }'
# 用樣式對awk處理的行進行過濾
awk 'NR < 5' #行號小於5
awk 'NR==1,NR==4 {print}' file #行號等於1和4的打印出來
awk '/linux/' #包含linux文本的行(可以用正則表達式來指定,超級強大)
awk '!/linux/' #不包含linux文本的行
# 設置定界符
# 使用-F來設置定界符(默認爲空格)
awk -F: '{print $NF}' /etc/passwd
# 讀取命令輸出
# 使用getline,將外部shell命令的輸出讀入到變量cmdout中;
echo | awk '{"grep root /etc/passwd" | getline cmdout; print cmdout }'
# 在awk中使用循環
for(i=0;i<10;i++){print $i;}
for(i in array){print array[i];}
# 以逆序的形式打印行:(tac命令的實現)
seq 9| awk '{lifo[NR] = $0; lno=NR} END{ for(;lno>-1;lno--){print lifo[lno];}}'
# awk實現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方式實現:
ls -lrt | awk '{print $6}'
# cut方式實現
ls -lrt | cut -f6
# 打印指定文本區域
# 確定行號
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常用內建函數
# index(string,search_string): 返回search_string在string中出現的位置
# sub(regex,replacement_str,string): 將正則匹配到的第一處內容替換爲replacement_str;
# match(regex,string): 檢查正則表達式是否能夠匹配字符串;
# length(string): 返回字符串長度
echo | awk '{"grep root /etc/passwd" | getline cmdout; print length(cmdout) }'
# printf 類似c語言中的printf,對輸出進行格式化
seq 10 | awk '{printf "->%4s\n", $1}'
12. 迭代文件中的行、單詞和字符
# 1. 迭代文件中的每一行
# while 循環法
while read line;doecho $line;done < file.txt改成子shell:cat file.txt | (while read line;do echo $line;done)
# awk法:
cat file.txt| awk ‘{print}’
# 2.迭代一行中的每一個單詞
for word in $line;do echo $word;done
# 3. 迭代每一個字符
# ${string:start_pos:num_of_chars}:從字符串中提取一個字符;(bash文本切片)
# ${#word}:返回變量word的長度
for((i=0;i<${#word};i++))doecho ${word:i:1);done
13. 壓縮與解壓
# 對於*.zip文件
zip -r examples.zip dir # 壓縮,-r 表示處理文件夾
unzip filename.zip # 解壓
# 對於*.tar文件
# 解壓
# 從1.15版本開始tar就可以自動識別壓縮的格式,故不需人爲區分壓縮格式就能正確解壓
# -x: extract 解壓
# -v: verbose 詳細信息
# -f: file(file=archieve) 文件
tar -xvf filename.tar.gz
tar -xvf filename.tar.bz2
tar -xvf filename.tar.xz
tar -xvf filename.tar.Z
# -C: 解壓到指定目錄
tar -xvf filename.tar.gz -C ./
# 壓縮
# -c, create 創建壓縮文件
# -z, --gzip 通過gzip壓縮的形式對文件進行歸檔
# -j, --bzip2 通過bzip2壓縮的形式對文件進行歸檔
tar -zcvf file.tar file1 # 壓縮file1文件,壓縮形式爲gzip
tar -cvf file.tar file1 file2 # 壓縮file1,file2文件,僅打包不使用壓縮
tar -cvf file.tar dir # 壓縮dir目錄
14. 一些實用的命令
# 從文件中隨機抽取n行
awk 'BEGIN{srand()} {print rand()"\t"$0}' input_file | sort -nk 1 | head -n line_num | awk -F "\t" '{print $2}'