Shell 文件的格式化與相關處理 printf、awk
格式化打印printf
使用場景:將數據格式化輸出
語法:printf '打印格式' 實際內容
選項與參數
關於格式方面的幾個特殊樣式
\n 換行符
\t 水平[tab]按鍵
\b 后退
%-ns -左對齊,沒有則右對齊,輸出寬度為n的字符,任何字符都會被顯示在 10 個字符寬的字符內,如果不足則自動以空格填充,超過會將內容全部顯示出來。
%[格式修飾符]nd 整型輸出
%ni i代表integer,多少位整數
%c 輸出一個字符
%N.nf N代表共輸出 N 位數,其中n位小數的
說明
1.printf不是管道命令
2.打印格式外面是單雙引號都可以
3.格式只指定了一個參數,但多出來的參數仍然會按照該格式輸出,格式化字符串會被重用
printf "%s\n" python shell
python
shell
4.如果沒有參數,會用默認值代替,那么%s用null代替,%d用0代替
格式修飾符
| 修飾符 | 說明 | 案例 |
|---|---|---|
| ' | 將千位分組分隔符應用於輸出的整數部分 | printf "%'d" 12345567890 12,345,567,890 |
| - | 左對齊 | printf '%5s\n' 123 空格空格123 printf '%-5s' 123 123 |
| + | 顯示符號 | printf '%+d\n' 11 +11 |
| 空格 | 有符號值為正,顯示空格,值為負顯示-,+標志會覆蓋空格標志 | printf '% d' -11 -11 printf '% d\n' 3 空格3 |
| # | 數字格式選擇符,進制輸出 | 下面說明 |
| 0 | 用0填充數字,而不是空格 | printf '%05d\n' 3 00003 |
| . | 限制輸出字符串的長度,默認長度超過設定值,字符串會全部顯示出來。 .n當打印的文本較長時會截斷文本留下n個字符,如果“.”后沒有指定寬度,默認為0,則不會打印文本。 如果“.”前也指定了寬度,則會在截斷文本后補足到指定的寬度。 |
printf "%4.2s\n" abcdc 空格空格ab |
| * | 寬度在字符串或數字之前通過參數指定,可以動態的指定打印文本的寬度。 | echo 5 "test" |
數字格式選擇
| 格式 | 說明 | 案例 |
|---|---|---|
| %#o | 八進制數總是以0開頭 | printf "%o" 123 173 輸入的十進制123轉換為八進制173 printf "%#o" 123 0173 |
| %#x、%#X | 十六進制數總是以0x/0X開頭 | printf "%x\n" 123 7b printf "%#x\n" 123 0x7b |
| %#g、%#G | 印的浮點數后面跟隨0,直到滿足精度所需的位數為止 | printf "%#g\n" 123 123.000 |
案例.格式化輸出文件內容
[ranan@hadoop102 ~]$ printf "%10s\t %5s\t %5\t \n" $(cat pringtf.txt)
輸出命令echo
Shell中的輸出命令有兩個printf與echo
| 區別 | echo | printf |
|---|---|---|
| 自動添加換行符 | √ | × |
| 設置輸出格式 | × | √ |
語法:echo [選項] 輸出的內容
選項
-n 不要在最后自動換行
-e 進行反斜杠轉義,字符串里面出現轉義字符將進行轉義

案例
輸出命令執行結果
echo `date` #注意是反斜杠
輸出內容到文件,文件若不存在則會創建一個文件
> 覆蓋寫
>> 追加寫
echo 123 >> text.txt
echo 輸出文件內容
'<'是重定向符,用於改變標准輸入的源(從鍵盤改為文件fileName);<fileName將fileName文件輸入到stdin中。
需要輸出可以使用cat命令
[ranan@hadoop102 bin]$ echo $(< myhadoop.sh)

awk數據處理工具
sed:一整行的處理
awk:一行分成數個字段來處理,提供一個類編程環境來修改和重新組織文件中的數據
awk 語言的最基本功能是在文件或字符串中基於指定規則瀏覽和抽取信息,完整的 awk 腳本通常用來格式化文本文件中的信息。
gawk程序是Unix中的原始awk程序的GNU版本,有一些擴展
語法格式
awk options '條件類型1{腳本1} 條件類型2{腳本2}..' filename
options
| 選項 | 描述 |
|---|---|
| -F fs | 分隔符 指定分隔符 |
| -f file | 從指定的文件中讀取腳本 |
| -v var=value | 指定一個變量值,這個會最先執行 |
注意點
-
如果沒有指定讀取文件,awk也可以從STDIN接受數據
awk可以處理后續接的文件,也可以讀取來自前一個命令的標准輸出。

EOF:End-of-File -
這里的引號只能是單引號
-
一個腳本里面多個命令,使用分號隔開
處理流程
1.讀入第一行,並將第一行的數據寫入$0,$1,$2等變量當中
2.根據條件,判斷是否需要進行后續的操作
3.完成所有操作和判斷
4.重復1~3直到所有數據處理完。
awk是以行為一次處理的單位,字段為最小的處理單位
AWK內置變量
| 類型 | 變量名 | 描述 |
|---|---|---|
| $n | 當前記錄的第n個字段,比如n為1表示第一個字段,n為2表示第二個字段 | |
| $0 | 表示執行過程中當前行的文本內容 | |
| FILENAME | 當前輸入文件的名。 | |
| NR | 目前awk所處理的第幾行數據,如果輸入兩個文件,第二個文件開始行數會接着上一個文件 | |
| FNR | 當前數據文件中的數據行數,如果輸入兩個文件,第二個文件開始行數會置0 | |
| NF(Field) | 每一行($0)擁有的字段總數 |
$NF
如果有5列,NF=5,$NF表示$5,也就是最后一個Field(列)的數據
關系表達式
一般使用關系表達式作為條件。
| 條件類型 | 條 件 | 說 明 |
|---|---|---|
| awk保留字 | BEGIN | 在 awk 程序一開始,尚未讀取任何數據之前執行。BEGIN 后的動作只在程序開始時執行一次 |
| awk保留字 | END | 在 awk 程序處理完所有數據,即將結束時執行。END 后的動作只在程序結束時執行一次 |
| 關系運算符 | > | 大於 |
| 關系運算符 | < | 小於 |
| 關系運算符 | >= | 大於等於 |
| 關系運算符 | <= | 小於等於 |
| 關系運算符 | == | 等於 |
| 關系運算符 | != | 不等於 |
| 關系運算符 | A~B | 判斷字符串 A 中是否包含能匹配 B 表達式的子字符串 |
| 關系運算符 | A!~B | 判斷字符串 A 中是否不包含能匹配 B 表達式的子字符串 |
| 正則表達式 | /正則/ | BRE和ERE都支持 |
字段和記錄分隔符變量
FS|目前的列的分隔符,默認是空白字符(空格或制表符)
OFS|輸出字段的分隔符
FIELDWIDTHS|由空格分隔一系列的數字,FIELDWIDTHS指定每個字段的長度
RS|輸入記錄分隔符,默認是\n,如RS=" " 表示空白行當作記錄分隔符
ORS|輸出記錄分隔符
案例1:改變輸出間隔符
這里我嘗試改變FS,以:為分隔符,輸出第一個和第二個元素(逗號分隔開),結果這里不太行
[ranan@hadoop102 ~]$ echo $PATH | awk '{print $0}'
/home/ranan/.local/bin:/home/ranan/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/module/hadoop-3.1.3/bin:/sbin
[ranan@hadoop102 ~]$ echo $PATH | awk '{FS=":"}{print $1,$2}'
/home/ranan/.local/bin:/home/ranan/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/module/hadoop-3.1.3/bin:/sbin
print 結尾自動加\n
printf 結尾不加\n
原因是awk執行的流程是
1.讀入第一行,並將第一行的數據寫入$0,$1,$2等變量當中
2.根據條件,判斷是否需要進行后續的操作
3.完成所有操作和判斷
意思是改變分隔符之前,第一行使用默認分隔符進行分割了,那么從第二行開始才是以:分割的。
這里可以通過添加條件類型解決
所以我們需要在讀入第一行之前,就處理分隔符
[ranan@hadoop102 ~]$ echo $PATH | awk 'BEGIN {FS=":"}{print $1,$2}'
/home/ranan/.local/bin /home/ranan/bin
假設我們需要輸出的字段之間以-划分
[ranan@hadoop102 ~]$ echo $PATH | awk 'BEGIN {FS=":";OFS="-"}{print $1,$2}'
/home/ranan/.local/bin-/home/ranan/bin
案例2.FIELDWIDTHS的使用
一旦設定了FIELDWIDTHS,FS會被忽略
按指定的寬度分隔數據,形成字符。
[ranan@MPI0 ~]$ cat data
1005.3247596.32
115-2.349194.00
-5810.1298100.1
ranan@MPI0 ~]$ awk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data
100 5.324 75 96.32
115 -2.34 91 94.00
-58 10.12 98 100.1
自定義變量
1.字母、數字、下划線,不能數字開頭。
2.awk變量區分大小寫
賦值
1.同Shell一樣,直接賦值,var=value
2.在命令上上賦值,這可以在不改變腳本代碼的情況下改變腳本的行為
[ranan@MPI0 ~]$ cat data
data11,data12,data13
data21,data22,data23
data31,data32,data33
[ranan@MPI0 ~]$ cat script
BEGIN{FS=","}{print $n}
[ranan@MPI0 ~]$ awk -f script n=2 data # 打印第二個字段 $2
data12
data22
data32
[ranan@MPI0 ~]$ awk -f script n=3 data # 打印第三個字段 $3
data13
data23
data33
假設BEGIN位置要輸出n,需要使用-v,且在命令行上-v命令行參數必須放在腳本代碼之前。
[ranan@MPI0 ~]$ cat script
BEGIN{FS=",";print n}{print $n}
[ranan@MPI0 ~]$ awk -f script n=2 data # 這里BEGIN會比賦值先執行
[ranan@MPI0 ~]$ awk -v n=2 -f script data # 需要加上-v才行
數組
awk語言使用關聯數組提供數組功能,索引值可以是任意文本字符串。
語法:var[index] = element
數組的遍歷
for(var in array){
statements;
}
刪除數組中的索引
delete array[index]
匹配操作符~
匹配操作符~的作用
對某字段使用正則表達式匹配
經常用於在數據文件中搜索特定元素。
匹配是否該行含有xxx
!~表示排除正則表達式的匹配
案例
匹配$1以data開頭的記錄
gawk '$1 ~ /^data/{ print $0}'
結構化命令
next 跳過當前行
awk中next語句使用:在循環逐行匹配,如果遇到next,就會跳過當前行,直接忽略下面語句。而進行下一行匹配。
awk 'NR%2==1{next}{print NR,$0;}' text.txt
if條件判斷式
語法
if(表達式){
動作1
動作2
}
else{
動作3
}
或者if(表達式)動作1;else動作2 # 單行if后面必須加上分號
[ranan@c105 ~]$ echo x | awk '{if(x>3)print "x大於3";else print"x不大於3" }'
x不大於3
循環
動作一句不用加分號
動作多句用分號隔開
while語法
while (條件){
動作
}
for循環語法
for (變量;條件;計數器){
動作
}
continue和break
break 跳出循環
continue 終止當前循環
內置函數
| 函數 | 描述 |
|---|---|
| int(x) | x的整數部分,取靠近零一側的最接近的整數 |
| rand() | 比0大比1小的隨機浮點數 |
字符串函數
| 函數 | 描述 | 注意點 |
|---|---|---|
| split(s,a[,r]) | 將s用FS字符或正則表達式r分開放到數組中,返回值是字段總數 | 可以對awk的字段再進行划分 |
