AWK基礎教程

前言

之前針對WorkerHub小程序做的數據分析文章 互聯網卷王花落誰家? 收到了一些小伙伴的回復,點名要學習數據分析,其實我也是一知半解,想著來寫幾篇文章簡單聊下我分析的過程。

首先是數據清洗和統計了,這塊我并沒有用諸如Python之類的腳本語言,雖然Python提供了很多強大的數據分析庫如Pandas、Numpy等,但是畢竟要麻煩一些,還要寫個腳本,裝一堆庫(PS:其實就是懶)。

我用的是一個老的Unix工具 AWK,雖然歷史比較久遠,但是它簡潔和豐富的功能可以稱之為神器,同時也是后臺同學必須要掌握的一個工具,畢竟通過日志緊急定位線上問題的時候,你不能跟老板說:等等我先寫個腳本,那老板原地暴斃了。

應用場景

AWK是1977年貝爾實驗室的三個兄弟( Alfred Aho、Peter Weinberger、 Brian Kernighan )搞出來的文本分析工具,這三個哥們的首字母拼起來就是AWK的名字了。

AWK處理文本就像其他語言處理數值一樣方便,所以經常被應用在文本處理領域。

比如日志分析、數據清洗、文本過濾、數據統計等。

同時AWK也是一門編程語言,不過它的命令行用法就可以滿足大多數的應用場景。

我們通??梢允褂靡恍蠥WK命令完成一個腳本的任務?。。?/p>

AWK所適用的文本處理通常都有一些共同&顯著的特點:

1. 輸入數據格式統一

比如日志,為了對日志進行上報、監控、統計分析,我們通常會采用一些分割手段來記錄日志 (或者json等易于統計的格式)。

例如如下日志采用”|”來分割日志。

# 日志格式:{服務}|{日期}|{業務}|{請求URL}|{返回狀態}|{請求耗時}|{請求參數}|{返回參數}...

比如CSV文件,采用”,”來分割。

# CSV格式:field1,field2,field3...

如果輸入數據不是固定格式,通常會使用sed、grep等工具來過濾、清洗為awk可以處理的形式。

2. 每一列代表固定含義,便于數據分析

輸入文件每一行的相同列類型一致,如果每一列含義不同,那就失去了數據分析的意義。

比如本文的第一個演示數據,第一列表示地區,第二列表示總人口等。

演示數據來源于國家統計局。

各地區戶口登記地在外鄉鎮街道的人口狀況

由于演示數據文件行數太多占用篇幅較長,以下演示均只展示前幾條數據。

$ cat population.txt|head -n 10
地區      合計      本縣/市/區  本省其他縣/市/區     省外
全國    260937942   90372599     84689006       85876337
北京    10498288    1582574      1871181        7044533
天津    4952225     1095282      865442         2991501
河北    8297279     4263957      2628649        1404673
山西    6764665     3643627      2189385        931653
內蒙古  7170889     2732591      2994117        1444181
遼寧    9310058     3899728      3623800        1786530
吉林    4462177     2604239      1401439        456499
黑龍江  5557828     2800727      2250704         506397

Let’s start ?。。?/strong>

基本用法

一個AWK程序的組成非常簡單,它的核心內容是:一個或多個 “模式–動作” 語句序列。

“模式–動作” 序列用單引號包起來,動作放在花括號里,再傳入輸入文件即可。

### 一個 模式-動作
awk 'pattern {action}' input_files

### 多個 模式-動作
awk 'pattern1 {action1} pattern2 {action2} pattern3 {action3} ...' input_files

AWK會每次讀取一個輸入行,對讀取到的每一行,按順序檢查每一個模式。

如果當前行符合模式,則執行對應動作。

所以AWK的工作原理就是按順序匹配模式然后執行動作。

可以想象到AWK偽代碼大概長這樣,我猜的(_)。

### AWK偽代碼  我猜的 (*^_^*)
while(getline(inputfile))
{
    if(模式1 == true)
    {
        動作1;
    }
    if(模式2 == true)
    {
        動作2;
    }
    ....
}

AWK在自動掃描輸入文件的同時, 也會按照分隔符(默認空格/Tab)把每一個輸入行切分成字段。

其中 $0 表示整行,$1,$2…$n 分別表示第一列,第二列…第N列。

大致的流程圖如下:

awk流程圖.png

大部分的工作都是AWK自動完成的:包括按行輸入,字段分割,字段存儲等。

所以我們只需要給出 “模式–動作” 序列就可以完成對文件的操作?。?!

來個 Hello World 吧,輸出 “hello” 和 整行 ($0)。

print 函數使用逗號分隔不同的參數,打印結果用空格符分隔,并且會自動換行。(類似于各大語言println函數)。

模式可以省略,表示匹配所有行。

$ awk '{print "hello",$0}' population.txt|head -n 5
hello 地區      合計      本縣/市/區  本省其他縣/市/區     省外
hello 全國    260937942   90372599     84689006       85876337
hello 北京    10498288    1582574      1871181        7044533
hello 天津    4952225     1095282      865442         2991501
hello 河北    8297279     4263957      2628649        1404673

AWK提供了很多有用的內置變量,如:

NR (Number Of Record) :表示讀取到的記錄數,即當前行號。

FILENAME :表示當前輸入的文件名。

NF (Number Of Field) :表示當前記錄的字段個數,即總共多少列。

我們通常用 $NF 提取當前行的最后一列。

如下例子所示,總共有5列,NF代表的就是第五列的值,等價于5,$(NF-1)表示倒數第二列的值。

$ awk '{print FILENAME,NR,$1,$3,NF,$NF}' population.txt|head -n 5
population.txt 1 地區 本縣/市/區 5 省外
population.txt 2 全國 90372599 5 85876337
population.txt 3 北京 1582574 5 7044533
population.txt 4 天津 1095282 5 2991501
population.txt 5 河北 4263957 5 1404673

常見的內建變量可以去附錄查閱:常見的內建變量 。

AWK也提供了格式化輸出函數,跟C語言的printf用法一樣。

$ awk '{printf "%s的外地總人口有:%d,省外人口有:%0.2f\n",$1,$2,$NF}' population.txt|tail -n 5
陜西的外地總人口有:5894416,省外人口有:974362.00
甘肅的外地總人口有:3112722,省外人口有:432833.00
青海的外地總人口有:1140954,省外人口有:318435.00
寧夏的外地總人口有:1534482,省外人口有:368451.00
新疆的外地總人口有:4276951,省外人口有:1791642.00

格式化規則可以參考:https://www.gnu.org/software/gawk/manual/html_node/Control-Letters.html 。

模式過濾

上面介紹了動作的使用,動作通常用來輸出展示。

模式用來過濾我們想要的記錄。

如下篩選(行號>1 且 第二列大于11074525)的行。

### AWK的變量也可以自由進行算術運算(加減乘除),比如 $2-$3
$ awk 'NR>1 && $2>11074525 {print NR,$1,$2,$2-$3}' population.txt
2 全國 260937942 170565343
11 上海 12685316 11016029
12 江蘇 18226819 13681789
13 浙江 19900863 15274032
17 山東 13698321 7123530
21 廣東 36806649 31390437
25 四川 11735152 6913850

AWK的字符串拼接跟shell一樣簡單粗暴,不需要使用任何運算符。

將兩個字符串并排放在一起就能實現拼接。

$ awk 'NR>1 {print NR,"開始_"$1"_結束"}' population.txt|head -n 5
2 開始_全國_結束
3 開始_北京_結束
4 開始_天津_結束
5 開始_河北_結束
6 開始_山西_結束

AWK還提供了很多有用的內置函數。

length(s):用來計算字符串s 的長度。

### 我的系統編碼 & 文件編碼均為UTF-8
$ awk 'length($1) > 6 {print $1,"占用長度:",length($1)}' population.txt
內蒙古 占用長度: 9
黑龍江 占用長度: 9

substr(s,p):求字符串s的子串,從位置p開始到末尾。

$ awk '{print $1,substr($1,4)}' population.txt|head -n 5
地區 區
全國 國
北京 京
天津 津
河北 北

常見的內建函數可以去附錄查閱:常見的內建函數 。

AWK還提供了一些特殊的模式,比如 BEGIN 和 END。這兩個模式不匹配任何輸入行。

當 awk讀取數據前,BEGIN 的語句開始執行,通常用于初始化。

例如我們可以用BEGIN來給輸出打印一個表頭。

### 多個 "模式-動作" 并排寫就行。
$ awk 'BEGIN{print "AREA TOTAL LOCAL OTHER OUTLAND"} NR>2{print}' population.txt|head -n 5
AREA TOTAL LOCAL OTHER OUTLAND
北京    10498288    1582574      1871181        7044533
天津    4952225     1095282      865442         2991501
河北    8297279     4263957      2628649        1404673
山西    6764665     3643627      2189385        931653

當所有輸入行被處理完畢,END 的語句開始執行。通常用來收尾。

例如我們可以統計一下第二列大于262005的省份,并在END進行打印。

$ awk 'NR>2 && $2>262005{count += 1} END{print count"個大于262005的省份"}' population.txt
30個大于262005的省份

同一個動作里的多個語句之間使用分號或者換行進行分割。

如下在BEGIN的動作中先指定輸出分隔符,接著打印表頭。

OFS (Output Formmat Separate) 也是一個內建變量:指定輸出字段分割符。

如下指定輸出時字段采用逗號進行分割。

$ awk 'BEGIN{OFS=",";print "AREA,TOTAL,LOCAL,OTHER,OUTLAND"} NR>2{print $1,$2,$3,$4,$5}' population.txt|head -n 5
AREA,TOTAL,LOCAL,OTHER,OUTLAND
北京,10498288,1582574,1871181,7044533
天津,4952225,1095282,865442,2991501
河北,8297279,4263957,2628649,1404673
山西,6764665,3643627,2189385,931653

AWK提供了范圍模式可以根據一個區間來匹配多個輸入行。

范圍模式由兩個被逗號分開的模式組成。

awk 'pattern1,pattern2 {action}' input_file

AWK從符合 pattern1 的行開始,到符合 pattern2 的行結束 (包括這兩行),對這其中的每一行執行action。

如下提取第五行到第十行之間地區的數據。

$ awk 'NR==5,NR==10" {print NR,$0}' population.txt
5 河北    8297279     4263957      2628649        1404673
6 山西    6764665     3643627      2189385        931653
7 內蒙古  7170889     2732591      2994117        1444181
8 遼寧    9310058     3899728      3623800        1786530
9 吉林    4462177     2604239      1401439        456499
10 黑龍江  5557828     2800727      2250704        506397

流程控制

前文提到了AWK也是一門編程語言,所以它支持很多編程語言特性,與C語言使用類似。

比如流程控制語句 if-else 、循環(for,while)。

比如數據結構數組等。

它們只能用在動作里。

如下示例使用if-else統計第二列大于4462177 和小于4462177的分別有多少行。

$ awk 'NR>2{if($2>4462177) more+=1; else less+=1} END{print "more:",more,"less:",less}' population.txt
more: 24 less: 7

上面這個例子也可以拆分成多個”模式-動作”來實現。

$ awk 'NR>2 && $2>4462177{more+=1} NR>2 && $2<=4462177{less+=1} END{print "more:",more,"less:",less}' population.txt
more: 24 less: 7

再來看個for循環的例子,打印AWK的命令行參數。

命令行參數在輸入文件后追加就可以傳入。

$ awk 'BEGIN {for(i=0;i<ARGC;i++) printf "%s\t",ARGV[i]; print ""}' population.txt abc def cdg
awk population.txt  abc def cdg

ARGC和ARGV也是AWK的內建變量,跟C語言的參數結構差不多。

ARGC:命令行參數的個數。

ARGV:命令行參數數組。

// 等價于C語言
int main(int argc, char *argv[])

AWK也支持使用數組進行數據存儲。

如下示例將對輸入行進行倒序輸出。

$ awk '{addr[NR]=$1} END{i=NR; while(i>0){print i,addr[i];i-=1}}' population.txt|head -n 5
33 新疆
32 寧夏
31 青海
30 甘肅
29 陜西

正則表達式

AWK 提供了對正則表達式的支持,正則表達式放在一對斜杠里:/regexpr/ 。

AWK使用 “~” 符號表示字符串匹配,”!~” 符號表示不匹配。

所以我們可以在模式中判斷一個字符串是否匹配一個正則表達式。

如下示例對 第一列含有 “北” 且第二列不包含 “88” 的行 進行打印。

$ awk '$1 ~ /北/ {print}' population.txt
北京    10498288    1582574      1871181        7044533
河北    8297279     4263957      2628649        1404673
湖北    9250228     4445565      3791051        1013612

$ awk '$1 ~ /北/ && $2 !~ /88/ {print}' population.txt
河北    8297279     4263957      2628649        1404673
湖北    9250228     4445565      3791051        1013612

如果判斷整行是否匹配,可以省略 “~” 的左值,如下所示。

###  /regexpr/ 等價于 $0  ~ /regexpr/
### !/regexpr/ 等價于 $0 !~ /regexpr/
$ awk '!/西/ && /88/ {print}' population.txt
北京    10498288    1582574      1871181        7044533
內蒙古  7170889     2732591      2994117         1444181
福建    11074525    3162036      3598887        4313602
湖南    7898815     4170436      3003397        724982
海南    1843430     586432       668535         588463
青海    1140954     351988       470531         318435

正則表達式的語法細節本文不過多說明。

以下是幾個小例子可以參考:

### 匹配小寫字母開頭的字符串
$ awk '/^[a-z]/' <<< "`echo -e "apple333\n1999fds\nhaode3232\n4343...\nhaoya328"`"
apple333
haode3232
haoya328

### 驗證是否是11位國內手機號碼
$ awk '/^1[3584][0-9]{9}$/' <<< "`echo -e "18894465939\n1364483882\n13644838825\n23443243432\n1334funny"`"
18894465939
13644838825

進階用法

接下來換個內容豐富的數據集來演示。

以下是 豆瓣電影評分Top250 的 CSV數據集。

### 數據格式:排行,電影名,評分,年份,導演,標簽,星級
$ cat douban_top250.csv|head -n 5
rank,title,rating_num,year,director,quote,star
1,肖申克的救贖,9.7,1994,弗蘭克·德拉邦特 Frank Darabont,希望讓人自由。,2304569
2,霸王別姬,9.6,1993,陳凱歌 Kaige Chen,風華絕代。,1709820
3,阿甘正傳,9.5,1994,羅伯特·澤米吉斯 Robert Zemeckis,一部美國近現代史。,1733112
4,這個殺手不太冷,9.4,1994,呂克·貝松 Luc Besson,怪蜀黍和小蘿莉不得不說的故事。,1913405

AWK默認按照 空格/Tab 對每一個輸入行進行切分。

我們可以使用 -F 參數進行指定分隔符,也支持多個分隔符。

### 指定分隔符
$ awk -F',' '{print $1,$2,$3}' douban_top250.csv|head -n 3
rank title rating_num
1 肖申克的救贖 9.7
2 霸王別姬 9.6

### 多個分隔符 可以看到評分被切分了
$ awk -F'[,.]' '{print $1,$2,$3,$4}' douban_top250.csv|head -n 3
rank title rating_num year
1 肖申克的救贖 9 7
2 霸王別姬 9 6

AWK支持使用shell重定向運算符 > 和 >> ,可以對文件進行拆分。

如下將 評分9以上的另存為douban_more_9.csv,評分9以下的為douban_less_9.csv。

$ awk -F',' 'NR>1 && $3>=9 {print $0 > "douban_more_9.csv"} NR >1 && $3<9 {print $0 > "douban_less_9.csv"}' douban_top250.csv

$ cat douban_less_9.csv|head -n 5
61,讓子彈飛,8.9,2010,姜文 Wen Jiang,你給我翻譯翻譯,神馬叫做TMD的驚喜。,1294845
63,綠皮書,8.9,2018,彼得·法雷里 Peter Farrelly,去除成見,需要勇氣。,1245160
65,本杰明·巴頓奇事,8.9,2008,大衛·芬奇 David Fincher,在時間之河里感受溺水之苦。,788815
68,看不見的客人,8.8,2016,奧里奧爾·保羅 Oriol Paulo,你以為你以為的就是你以為的。,965038
69,西西里的美麗傳說,8.9,2000,朱塞佩·托納多雷 Giuseppe Tornatore,美麗無罪。,781719

$ cat douban_more_9.csv|head -n 5
1,肖申克的救贖,9.7,1994,弗蘭克·德拉邦特 Frank Darabont,希望讓人自由。,2304569
2,霸王別姬,9.6,1993,陳凱歌 Kaige Chen,風華絕代。,1709820
3,阿甘正傳,9.5,1994,羅伯特·澤米吉斯 Robert Zemeckis,一部美國近現代史。,1733112
4,這個殺手不太冷,9.4,1994,呂克·貝松 Luc Besson,怪蜀黍和小蘿莉不得不說的故事。,1913405
5,泰坦尼克號,9.4,1997,詹姆斯·卡梅隆 James Cameron,失去的才是永恒的。,1695453

AWK也支持三目表達式,上面語句等價于下面。

$ awk -F',' 'NR>1 {print $0 > ($3>=9 ? "douban_more_9.csv":"douban_less_9.csv")}' douban_top250.csv

同時我們可以對文件進行批量處理。

比如下面提取第二列和最后一列進行MySQL入庫。

這在數據量大的時候很管用。

比如幾萬、幾億的數據可以快速轉化為SQL語句。

### 注意 雙引號只需要斜杠轉義:\"
### 單引號除了斜杠轉義還要用''包圍起來: '\''
$ awk -F',' 'NR>1 {print "insert into `movie` (name,star) values ('\''"$2"'\'','\''"$NF"'\'');" > "movie.sql"}' douban_top250.csv

cat movie.sql|head -n 5
insert into `movie` (name,star) values ('肖申克的救贖','2304569');
insert into `movie` (name,star) values ('霸王別姬','1709820');
insert into `movie` (name,star) values ('阿甘正傳','1733112');
insert into `movie` (name,star) values ('這個殺手不太冷','1913405');
insert into `movie` (name,star) values ('泰坦尼克號','1695453');

統計Top250里各個評分所占數量。

$ awk -F',' 'NR>1{count[$3]++} END{for(i in count) print "豆瓣電影Top250里評分",i,"的電影有",count[i],"個"}' douban_top250.csv
豆瓣電影Top250里評分 9.0 的電影有 20 個
豆瓣電影Top250里評分 9.1 的電影有 23 個
豆瓣電影Top250里評分 9.2 的電影有 19 個
豆瓣電影Top250里評分 9.3 的電影有 17 個
豆瓣電影Top250里評分 9.4 的電影有 6 個
豆瓣電影Top250里評分 9.5 的電影有 4 個
豆瓣電影Top250里評分 9.6 的電影有 2 個
豆瓣電影Top250里評分 9.7 的電影有 1 個
豆瓣電影Top250里評分 8.3 的電影有 1 個
豆瓣電影Top250里評分 8.4 的電影有 3 個
豆瓣電影Top250里評分 8.5 的電影有 11 個
豆瓣電影Top250里評分 8.6 的電影有 25 個
豆瓣電影Top250里評分 8.7 的電影有 42 個
豆瓣電影Top250里評分 8.8 的電影有 38 個
豆瓣電影Top250里評分 8.9 的電影有 38 個

找出Top250里拍過多個電影的導演。

$ awk -F',' 'NR>1{print $5}' douban_top250.csv|sort|uniq -c|sort -rn|head -n 5
   8 宮崎駿 Hayao Miyazaki
   7 克里斯托弗·諾蘭 Christopher Nolan
   6 史蒂文·斯皮爾伯格 Steven Spielberg
   5 王家衛 Kar Wai Wong
   5 李安 Ang Lee

找出Top250里即拍過評分9以上 又拍過9分以下的導演。

即求 douban_less_9.csv 和 douban_more_9.csv 兩個文件的交集。

$ awk -F',' 'NR==FNR{map[$5]++} NR>FNR{if($5 in map)print $5}' douban_less_9.csv douban_more_9.csv|sort|uniq -c
   1 Chris Columbus
   2 李安 Ang Lee
   1 姜文 Wen Jiang
   1 大衛·芬奇 David Fincher
   1 羅伯·萊納 Rob Reiner
   1 劉偉強 / 麥兆輝
   1 黑澤明 Akira Kurosawa
   1 楊德昌 Edward Yang
   4 宮崎駿 Hayao Miyazaki
   2 劉鎮偉 Jeffrey Lau
   1 詹姆斯·卡梅隆 James Cameron
   2 朱塞佩·托納多雷 Giuseppe Tornatore
   3 史蒂文·斯皮爾伯格 Steven Spielberg
   1 是枝裕和 Hirokazu Koreeda
   2 弗朗西斯·福特·科波拉 Francis Ford Coppola
   3 克里斯托弗·諾蘭 Christopher Nolan

數組的key可以字符串拼接,這樣可以間接實現二維數組的邏輯。

$ awk -F',' 'NR==2,NR==5{a[$1"-"$2]=$3} END {for (i in a) print i, a[i]}' douban_top250.csv
1-肖申克的救贖 9.7
3-阿甘正傳 9.5
4-這個殺手不太冷 9.4
2-霸王別姬 9.6

數據統計的大部分需求都可以用AWK快速的實現。

比如:過濾、統計、聚合、并集、交集、差集等。

快來試試吧!??!

本文所有用到的數據集可以在奇跡狗狗后臺回復:”awk” 進行獲取

附錄

常見的內建變量

內建變量 補充默認值 含義
NF 當前記錄的字段個數,即總共多少列
NR 讀取到的記錄數,即當前行號
FNR 當前輸入文件的記錄個數,區別于NR,NR表示整體的記錄數,FNR表示當前文件
ARGC 命令行參數的個數
ARGV 命令行參數數組
FS 指定輸入行的字段分割符
FILENAME 當前輸入文件名
OFS 指定輸出字段分割符
ORS 指定輸出的記錄分割符 默認是換行 "\n"
RS 指定輸入行的記錄分割符 默認是換行 "\n"

常見的內建函數

函數 含義
length(s) 字符串s長度
tolower(s) 把字符串轉為小寫
substr(s, p) 字符串s的子串,從位置p開始到末尾
split(s, a, fs) 把字符串s根據fs進行分割,存到數組a中
sprintf(fmt,expr-list) 跟C語言sprintf一樣,用于字符串格式化
int(x) 取x 的整數部分
sin(x) / cos(x) / sqrt(x) 正弦 / 余弦 / 平方根
rand() 隨機數 配合 srand(x)使用 x 是 rand() 的隨機數種子
match(s,r) 正則表達式匹配,測試 s 是否包含能被 r 匹配的子串
sub(r,s) 正則表達式替換,將 $0 的第一個被r匹配的子串替換為s
gsub(r,s) 正則表達式全局替換,將 $0 中所有被r匹配的子串替換為s
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容