Bash shell 基礎(chǔ)

摘抄自廖雪峰

變量

環(huán)境變量

env命令或printenv命令,可以顯示所有環(huán)境變量痹雅。

$ env
# 或者
$ printenv

下面是一些常見的環(huán)境變量仰担。

  • BASHPID:Bash 進程的進程 ID。
  • BASHOPTS:當前 Shell 的參數(shù)绩社,可以用shopt命令修改摔蓝。
  • DISPLAY:圖形環(huán)境的顯示器名字,通常是:0愉耙,表示 X Server 的第一個顯示器贮尉。
  • EDITOR:默認的文本編輯器。
  • HOME:用戶的主目錄朴沿。
  • HOST:當前主機的名稱猜谚。
  • IFS:詞與詞之間的分隔符,默認為空格悯仙。
  • LANG:字符集以及語言編碼龄毡,比如zh_CN.UTF-8
  • PATH:由冒號分開的目錄列表锡垄,當輸入可執(zhí)行程序名后沦零,會搜索這個目錄列表。
  • PS1:Shell 提示符货岭。
  • PS2: 輸入多行命令時路操,次要的 Shell 提示符。
  • PWD:當前工作目錄千贯。
  • RANDOM:返回一個0到32767之間的隨機數(shù)屯仗。
  • SHELL:Shell 的名字。
  • SHELLOPTS:啟動當前 Shell 的set命令的參數(shù)搔谴。
  • TERM:終端類型名魁袜,即終端仿真器所用的協(xié)議。
  • UID:當前用戶的 ID 編號。
  • USER:當前用戶的用戶名峰弹。

很多環(huán)境變量很少發(fā)生變化店量,而且是只讀的,可以視為常量鞠呈。由于它們的變量名全部都是大寫融师,所以傳統(tǒng)上,如果用戶要自己定義一個常量蚁吝,也會使用全部大寫的變量名旱爆。

查看單個環(huán)境變量的值,可以使用printenv命令或echo命令窘茁。

$ printenv PATH
# 或者
$ echo $PATH

注意怀伦,printenv命令后面的變量名,不用加前綴$

自定義變量

自定義變量是用戶在當前 Shell 里面自己定義的變量,僅在當前 Shell 可用桑腮。一旦退出當前 Shell,該變量就不存在了吴攒。

set命令可以顯示所有變量(包括環(huán)境變量和自定義變量),以及所有的 Bash 函數(shù)砂蔽。

$ set

創(chuàng)建變量

用戶創(chuàng)建變量的時候洼怔,變量名必須遵守下面的規(guī)則。

  • 字母左驾、數(shù)字和下劃線字符組成镣隶。
  • 第一個字符必須是一個字母或一個下劃線,不能是數(shù)字诡右。
  • 不允許出現(xiàn)空格和標點符號安岂。

變量聲明的語法如下。

variable=value

上面命令中帆吻,等號左邊是變量名域那,右邊是變量。注意猜煮,等號兩邊不能有空格次员。(于 python 不同,= 兩邊有空格)

如果變量的值包含空格王带,則必須將值放在引號中淑蔚。

myvar="hello world"

Bash 沒有數(shù)據(jù)類型的概念,所有的變量值都是字符串愕撰。

下面是一些自定義變量的例子刹衫。

a=z                     # 變量 a 賦值為字符串 z
b="a string"            # 變量值包含空格醋寝,就必須放在引號里面
c="a string and $b"     # 變量值可以引用其他變量的值
d="\t\ta string\n"      # 變量值可以使用轉(zhuǎn)義字符
e=$(ls -l foo.txt)      # 變量值可以是命令的執(zhí)行結(jié)果
f=$((5 * 7))            # 變量值可以是數(shù)學運算的結(jié)果

變量可以重復(fù)賦值,后面的賦值會覆蓋前面的賦值绪妹。

$ foo=1
$ foo=2
$ echo $foo
2

上面例子中甥桂,變量foo的第二次賦值會覆蓋第一次賦值柿究。

如果同一行定義多個變量邮旷,必須使用分號(;)分隔。

$ foo=1;bar=2

上面例子中蝇摸,同一行定義了foobar兩個變量婶肩。

讀取變量

讀取變量的時候,直接在變量名前加上$就可以了貌夕。

$ foo=bar
$ echo $foo
bar

每當 Shell 看到以$開頭的單詞時律歼,就會嘗試讀取這個變量名對應(yīng)的值。

如果變量不存在啡专,Bash 不會報錯险毁,而會輸出空字符。

讀取變量的時候们童,變量名也可以使用花括號{}包圍畔况,比如$a也可以寫成${a}。這種寫法可以用于變量名與其他字符連用的情況慧库。

$ a=foo
$ echo $a_file

$ echo ${a}_file
foo_file

上面代碼中跷跪,變量名a_file不會有任何輸出,因為 Bash 將其整個解釋為變量齐板,而這個變量是不存在的吵瞻。只有用花括號區(qū)分$a,Bash 才能正確解讀甘磨。

事實上橡羞,讀取變量的語法$foo,可以看作是${foo}的簡寫形式济舆。

如果變量的值本身也是變量卿泽,可以使用${!varname}的語法,讀取最終的值吗冤。

$ myvar=USER
$ echo ${!myvar}
ruanyf

上面的例子中又厉,變量myvar的值是USER${!myvar}的寫法將其展開成最終的值椎瘟。

如果變量值包含連續(xù)空格(或制表符和換行符)覆致,最好放在雙引號里面讀取。

$ a="1 2  3"
$ echo $a
1 2 3
$ echo "$a"
1 2  3

上面示例中肺蔚,變量a的值包含兩個連續(xù)空格煌妈。如果直接讀取,Shell 會將連續(xù)空格合并成一個。只有放在雙引號里面讀取璧诵,才能保持原來的格式汰蜘。

刪除變量

unset命令用來刪除一個變量。

unset NAME

這個命令不是很有用之宿。因為不存在的 Bash 變量一律等于空字符串族操,所以即使unset命令刪除了變量,還是可以讀取這個變量比被,值為空字符串色难。

所以,刪除一個變量等缀,也可以將這個變量設(shè)成空字符串枷莉。

$ foo=''
$ foo=

上面兩種寫法,都是刪除了變量foo尺迂。由于不存在的值默認為空字符串笤妙,所以后一種寫法可以在等號右邊不寫任何值。

輸出變量噪裕,export 命令

用戶創(chuàng)建的變量僅可用于當前 Shell蹲盘,子 Shell 默認讀取不到父 Shell 定義的變量。為了把變量傳遞給子 Shell州疾,需要使用export命令辜限。這樣輸出的變量,對于子 Shell 來說就是環(huán)境變量严蓖。

export命令用來向子 Shell 輸出變量薄嫡。

NAME=foo
export NAME

上面命令輸出了變量NAME。變量的賦值和輸出也可以在一個步驟中完成颗胡。

export NAME=value

上面命令執(zhí)行后毫深,當前 Shell 及隨后新建的子 Shell,都可以讀取變量$NAME毒姨。

子 Shell 如果修改繼承的變量哑蔫,不會影響父 Shell。

# 輸出變量 $foo
$ export foo=bar

# 新建子 Shell
$ bash

# 讀取 $foo
$ echo $foo
bar

# 修改繼承的變量
$ foo=baz

# 退出子 Shell
$ exit

# 讀取 $foo
$ echo $foo
bar

上面例子中弧呐,子 Shell 修改了繼承的變量$foo闸迷,對父 Shell 沒有影響。

特殊變量

Bash 提供一些特殊變量俘枫。這些變量的值由 Shell 提供腥沽,用戶不能進行賦值。

(1)$?

$?為上一個命令的退出碼鸠蚪,用來判斷上一個命令是否執(zhí)行成功今阳。返回值是0师溅,表示上一個命令執(zhí)行成功;如果不是零盾舌,表示上一個命令執(zhí)行失敗墓臭。

$ ls doesnotexist
ls: doesnotexist: No such file or directory

$ echo $?
1

上面例子中,ls命令查看一個不存在的文件妖谴,導(dǎo)致報錯窿锉。$?為1,表示上一個命令執(zhí)行失敗窖维。

(2)$$

$$為當前 Shell 的進程 ID榆综。

$ echo $$
10662

這個特殊變量可以用來命名臨時文件。

LOGFILE=/tmp/output_log.$$

(3)$_

$_為上一個命令的最后一個參數(shù)铸史。

$ grep dictionary /usr/share/dict/words
dictionary

$ echo $_
/usr/share/dict/words

(4)$!

$!為最近一個后臺執(zhí)行的異步命令的進程 ID。

$ firefox &
[1] 11064

$ echo $!
11064

上面例子中怯伊,firefox是后臺運行的命令琳轿,$!返回該命令的進程 ID。

(5)$0

$0為當前 Shell 的名稱(在命令行直接執(zhí)行時)或者腳本名(在腳本中執(zhí)行時)耿芹。

$ echo $0
bash

上面例子中崭篡,$0返回當前運行的是 Bash。

(6)$-

$-為當前 Shell 的啟動參數(shù)吧秕。

$ echo $-
himBHs

(7)$@$#

$#表示腳本的參數(shù)數(shù)量琉闪,$@表示腳本的參數(shù)值,參見腳本一章砸彬。

變量的默認值

Bash 提供四個特殊語法颠毙,跟變量的默認值有關(guān),目的是保證變量不為空砂碉。

${varname:-word}

上面語法的含義是蛀蜜,如果變量varname存在且不為空,則返回它的值增蹭,否則返回word滴某。它的目的是返回一個默認值,比如${count:-0}表示變量count不存在時返回0滋迈。

${varname:=word}

上面語法的含義是霎奢,如果變量varname存在且不為空,則返回它的值饼灿,否則將它設(shè)為word幕侠,并且返回word。它的目的是設(shè)置變量的默認值赔退,比如${count:=0}表示變量count不存在時返回0橙依,且將count設(shè)為0证舟。

${varname:+word}

上面語法的含義是,如果變量名存在且不為空窗骑,則返回word女责,否則返回空值。它的目的是測試變量是否存在创译,比如${count:+1}表示變量count存在時返回1(表示true)抵知,否則返回空值。

${varname:?message}

上面語法的含義是软族,如果變量varname存在且不為空刷喜,則返回它的值,否則打印出varname: message立砸,并中斷腳本的執(zhí)行掖疮。如果省略了message,則輸出默認的信息“parameter null or not set.”颗祝。它的目的是防止變量未定義浊闪,比如${count:?"undefined!"}表示變量count未定義時就中斷執(zhí)行,拋出錯誤螺戳,返回給定的報錯信息undefined!搁宾。

上面四種語法如果用在腳本中,變量名的部分可以用數(shù)字19倔幼,表示腳本的參數(shù)盖腿。

filename=${1:?"filename missing."}

上面代碼出現(xiàn)在腳本中,1表示腳本的第一個參數(shù)损同。如果該參數(shù)不存在翩腐,就退出腳本并報錯。

declare 命令

declare命令可以聲明一些特殊類型的變量揖庄,為變量設(shè)置一些限制栗菜,比如聲明只讀類型的變量和整數(shù)類型的變量。

它的語法形式如下蹄梢。

declare OPTION VARIABLE=value

declare命令的主要參數(shù)(OPTION)如下疙筹。

  • -a:聲明數(shù)組變量。
  • -f:輸出所有函數(shù)定義禁炒。
  • -F:輸出所有函數(shù)名而咆。
  • -i:聲明整數(shù)變量。
  • -l:聲明變量為小寫字母幕袱。
  • -p:查看變量信息暴备。
  • -r:聲明只讀變量。
  • -u:聲明變量為大寫字母们豌。
  • -x:該變量輸出為環(huán)境變量涯捻。

declare命令如果用在函數(shù)中浅妆,聲明的變量只在函數(shù)內(nèi)部有效,等同于local命令障癌。

不帶任何參數(shù)時凌外,declare命令輸出當前環(huán)境的所有變量,包括函數(shù)在內(nèi)涛浙,等同于不帶有任何參數(shù)的set命令康辑。

$ declare

(1)-i參數(shù)

-i參數(shù)聲明整數(shù)變量以后,可以直接進行數(shù)學運算轿亮。

$ declare -i val1=12 val2=5
$ declare -i result
$ result=val1*val2
$ echo $result
60

上面例子中疮薇,如果變量result不聲明為整數(shù),val1*val2會被當作字面量我注,不會進行整數(shù)運算按咒。另外,val1val2其實不需要聲明為整數(shù)仓手,因為只要result聲明為整數(shù)胖齐,它的賦值就會自動解釋為整數(shù)運算。

注意嗽冒,一個變量聲明為整數(shù)以后,依然可以被改寫為字符串补履。

$ declare -i var=12
$ var=foo
$ echo $var
0

上面例子中添坊,變量var聲明為整數(shù),覆蓋以后箫锤,Bash 不會報錯贬蛙,但會賦以不確定的值,上面的例子中可能輸出0谚攒,也可能輸出的是3阳准。

(2)-x參數(shù)

-x參數(shù)等同于export命令,可以輸出一個變量為子 Shell 的環(huán)境變量馏臭。

$ declare -x foo
# 等同于
$ export foo

(3)-r參數(shù)

-r參數(shù)可以聲明只讀變量野蝇,無法改變變量值,也不能unset變量括儒。

$ declare -r bar=1

$ bar=2
bash: bar:只讀變量
$ echo $?
1

$ unset bar
bash: bar:只讀變量
$ echo $?
1

上面例子中绕沈,后兩個賦值語句都會報錯,命令執(zhí)行失敗帮寻。

(4)-u參數(shù)

-u參數(shù)聲明變量為大寫字母乍狐,可以自動把變量值轉(zhuǎn)成大寫字母。

$ declare -u foo
$ foo=upper
$ echo $foo
UPPER

(5)-l參數(shù)

-l參數(shù)聲明變量為小寫字母固逗,可以自動把變量值轉(zhuǎn)成小寫字母浅蚪。

$ declare -l bar
$ bar=LOWER
$ echo $bar
lower

(6)-p參數(shù)

-p參數(shù)輸出變量信息藕帜。

$ foo=hello
$ declare -p foo
declare -- foo="hello"
$ declare -p bar
bar:未找到

上面例子中,declare -p可以輸出已定義變量的值惜傲,對于未定義的變量洽故,會提示找不到。

如果不提供變量名操漠,declare -p輸出所有變量的信息收津。

$ declare -p

(7)-f參數(shù)

-f參數(shù)輸出當前環(huán)境的所有函數(shù),包括它的定義浊伙。

$ declare -f

(8)-F參數(shù)

-F參數(shù)輸出當前環(huán)境的所有函數(shù)名撞秋,不包含函數(shù)定義。

$ declare -F

readonly 命令

readonly命令等同于declare -r嚣鄙,用來聲明只讀變量吻贿,不能改變變量值,也不能unset變量哑子。

$ readonly foo=1
$ foo=2
bash: foo:只讀變量
$ echo $?
1

上面例子中舅列,更改只讀變量foo會報錯,命令執(zhí)行失敗卧蜓。

readonly命令有三個參數(shù)帐要。

  • -f:聲明的變量為函數(shù)名。
  • -p:打印出所有的只讀變量弥奸。
  • -a:聲明的變量為數(shù)組榨惠。

Bash 啟動環(huán)境

Session

用戶每次使用 Shell,都會開啟一個與 Shell 的 Session(對話)盛霎。

Session 有兩種類型:登錄 Session 和非登錄 Session赠橙,也可以叫做 login shell 和 non-login shell。

登錄 Session

登錄 Session 是用戶登錄系統(tǒng)以后愤炸,系統(tǒng)為用戶開啟的原始 Session期揪,通常需要用戶輸入用戶名和密碼進行登錄。

登錄 Session 一般進行整個系統(tǒng)環(huán)境的初始化规个,啟動的初始化腳本依次如下凤薛。

  • /etc/profile:所有用戶的全局配置腳本。
  • /etc/profile.d目錄里面所有.sh文件
  • ~/.bash_profile:用戶的個人配置腳本绰姻。如果該腳本存在枉侧,則執(zhí)行完就不再往下執(zhí)行。
  • ~/.bash_login:如果~/.bash_profile沒找到狂芋,則嘗試執(zhí)行這個腳本(C shell 的初始化腳本)榨馁。如果該腳本存在,則執(zhí)行完就不再往下執(zhí)行帜矾。
  • ~/.profile:如果~/.bash_profile~/.bash_login都沒找到翼虫,則嘗試讀取這個腳本(Bourne shell 和 Korn shell 的初始化腳本)屑柔。

Linux 發(fā)行版更新的時候,會更新/etc里面的文件珍剑,比如/etc/profile掸宛,因此不要直接修改這個文件。如果想修改所有用戶的登陸環(huán)境招拙,就在/etc/profile.d目錄里面新建.sh腳本唧瘾。

如果想修改你個人的登錄環(huán)境,一般是寫在~/.bash_profile里面别凤。下面是一個典型的.bash_profile文件饰序。

# .bash_profile
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
PATH=$PATH:$HOME/bin

SHELL=/bin/bash
MANPATH=/usr/man:/usr/X11/man
EDITOR=/usr/bin/vi
PS1='\h:\w\$ '
PS2='> '

if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

export PATH
export EDITOR

可以看到,這個腳本定義了一些最基本的環(huán)境變量规哪,然后執(zhí)行了~/.bashrc求豫。

bash命令的--login參數(shù),會強制執(zhí)行登錄 Session 會執(zhí)行的腳本诉稍。

$ bash --login

bash命令的--noprofile參數(shù)蝠嘉,會跳過上面這些 Profile 腳本。

$ bash --noprofile

非登錄 Session

非登錄 Session 是用戶進入系統(tǒng)以后杯巨,手動新建的 Session蚤告,這時不會進行環(huán)境初始化。比如服爷,在命令行執(zhí)行bash命令罩缴,就會新建一個非登錄 Session。

非登錄 Session 的初始化腳本依次如下层扶。

  • /etc/bash.bashrc:對全體用戶有效。
  • ~/.bashrc:僅對當前用戶有效烙荷。

對用戶來說镜会,~/.bashrc通常是最重要的腳本。非登錄 Session 默認會執(zhí)行它终抽,而登錄 Session 一般也會通過調(diào)用執(zhí)行它戳表。每次新建一個 Bash 窗口,就相當于新建一個非登錄 Session昼伴,所以~/.bashrc每次都會執(zhí)行匾旭。注意,執(zhí)行腳本相當于新建一個非互動的 Bash 環(huán)境圃郊,但是這種情況不會調(diào)用~/.bashrc价涝。

bash命令的--norc參數(shù),可以禁止在非登錄 Session 執(zhí)行~/.bashrc腳本持舆。

$ bash --norc

bash命令的--rcfile參數(shù)色瘩,指定另一個腳本代替.bashrc伪窖。

$ bash --rcfile testrc

.bash_logout

~/.bash_logout腳本在每次退出 Session 時執(zhí)行,通常用來做一些清理工作和記錄工作居兆,比如刪除臨時文件覆山,記錄用戶在本次 Session 花費的時間。

如果沒有退出時要執(zhí)行的命令泥栖,這個文件也可以不存在簇宽。

啟動選項

為了方便 Debug,有時在啟動 Bash 的時候吧享,可以加上啟動參數(shù)魏割。

  • -n:不運行腳本,只檢查是否有語法錯誤耙蔑。
  • -v:輸出每一行語句運行結(jié)果前见妒,會先輸出該行語句。
  • -x:每一個命令處理之前甸陌,先輸出該命令须揣,再執(zhí)行該命令。
$ bash -n scriptname
$ bash -v scriptname
$ bash -x scriptname

鍵盤綁定

Bash 允許用戶定義自己的快捷鍵钱豁。全局的鍵盤綁定文件默認為/etc/inputrc耻卡,你可以在主目錄創(chuàng)建自己的鍵盤綁定文件.inputrc文件。如果定義了這個文件牲尺,需要在其中加入下面這行卵酪,保證全局綁定不會被遺漏。

$include /etc/inputrc

.inputrc文件里面的快捷鍵谤碳,可以像這樣定義溃卡,"\C-t":"pwd\n"表示將Ctrl + t綁定為運行pwd命令。

模式擴展

Shell 接收到用戶輸入的命令以后蜒简,會根據(jù)空格將用戶的輸入瘸羡,拆分成一個個詞元(token)。然后搓茬,Shell 會擴展詞元里面的特殊字符犹赖,擴展完成后才會調(diào)用相應(yīng)的命令。

這種特殊字符的擴展卷仑,稱為模式擴展(globbing)峻村。其中有些用到通配符,又稱為通配符擴展(wildcard expansion)锡凝。Bash 一共提供八種擴展粘昨。

  • 波浪線擴展
  • ? 字符擴展
  • * 字符擴展
  • 方括號擴展
  • 大括號擴展
  • 變量擴展
  • 子命令擴展
  • 算術(shù)擴展

本章介紹這八種擴展。

Bash 是先進行擴展,再執(zhí)行命令雾棺。因此膊夹,擴展的結(jié)果是由 Bash 負責的,與所要執(zhí)行的命令無關(guān)捌浩。命令本身并不存在參數(shù)擴展放刨,收到什么參數(shù)就原樣執(zhí)行。這一點務(wù)必需要記住尸饺。

模塊擴展的英文單詞是globbing进统,這個詞來自于早期的 Unix 系統(tǒng)有一個/etc/glob文件,保存擴展的模板浪听。后來 Bash 內(nèi)置了這個功能螟碎,但是這個名字就保留了下來。

模式擴展與正則表達式的關(guān)系是迹栓,模式擴展早于正則表達式出現(xiàn)掉分,可以看作是原始的正則表達式。它的功能沒有正則那么強大靈活克伊,但是優(yōu)點是簡單和方便酥郭。

Bash 允許用戶關(guān)閉擴展。

$ set -o noglob
# 或者
$ set -f

下面的命令可以重新打開擴展愿吹。

$ set +o noglob
# 或者
$ set +f

波浪線擴展

波浪線~會自動擴展成當前用戶的主目錄不从。

$ echo ~
/home/me

~/dir表示擴展成主目錄的某個子目錄,dir是主目錄里面的一個子目錄名犁跪。

# 進入 /home/me/foo 目錄
$ cd ~/foo

~user表示擴展成用戶user的主目錄椿息。

$ echo ~foo
/home/foo

$ echo ~root
/root

上面例子中,Bash 會根據(jù)波浪號后面的用戶名坷衍,返回該用戶的主目錄寝优。

如果~useruser是不存在的用戶名,則波浪號擴展不起作用枫耳。

$ echo ~nonExistedUser
~nonExistedUser

? 字符擴展

?字符代表文件路徑里面的任意單個字符倡勇,不包括空字符。比如嘉涌,Data???匹配所有Data后面跟著三個字符的文件名。

# 存在文件 a.txt 和 b.txt
$ ls ?.txt
a.txt b.txt

* 字符擴展

*字符代表文件路徑里面的任意數(shù)量的任意字符夸浅,包括零個字符仑最。

# 存在文件 a.txt、b.txt 和 ab.txt
$ ls *.txt
a.txt b.txt ab.txt

上面例子中帆喇,*.txt代表后綴名為.txt的所有文件警医。

方括號擴展

方括號擴展的形式是[...],只有文件確實存在的前提下才會擴展。如果文件不存在预皇,就會原樣輸出。括號之中的任意一個字符。比如匀钧,[aeiou]可以匹配五個元音字母中的任意一個梅鹦。

# 存在文件 a.txt 和 b.txt
$ ls [ab].txt
a.txt b.txt

# 只存在文件 a.txt
$ ls [ab].txt
a.txt

上面例子中,[ab]可以匹配ab鲁豪,前提是確實存在相應(yīng)的文件潘悼。

[start-end] 擴展

方括號擴展有一個簡寫形式[start-end],表示匹配一個連續(xù)的范圍爬橡。比如治唤,[a-c]等同于[abc][0-9]匹配[0123456789]糙申。

# 存在文件 a.txt宾添、b.txt 和 c.txt
$ ls [a-c].txt
a.txt
b.txt
c.txt

# 存在文件 report1.txt、report2.txt 和 report3.txt
$ ls report[0-9].txt
report1.txt
report2.txt
report3.txt
...

下面是一些常用簡寫的例子柜裸。

  • [a-z]:所有小寫字母缕陕。
  • [a-zA-Z]:所有小寫字母與大寫字母。
  • [a-zA-Z0-9]:所有小寫字母粘室、大寫字母與數(shù)字榄檬。
  • [abc]*:所有以ab衔统、c字符之一開頭的文件名鹿榜。
  • program.[co]:文件program.c與文件program.o
  • BACKUP.[0-9][0-9][0-9]:所有以BACKUP.開頭锦爵,后面是三個數(shù)字的文件名舱殿。

這種簡寫形式有一個否定形式[!start-end],表示匹配不屬于這個范圍的字符险掀。比如沪袭,[!a-zA-Z]表示匹配非英文字母的字符。

$ ls report[!1–3].txt
report4.txt report5.txt

上面代碼中樟氢,[!1-3]表示排除1冈绊、2和3。

大括號擴展

大括號擴展{...}表示分別擴展成大括號里面的所有值埠啃,各個值之間使用逗號分隔死宣。比如,{1,2,3}擴展成1 2 3碴开。

$ echo {1,2,3}
1 2 3

$ echo d{a,e,i,u,o}g
dag deg dig dug dog

$ echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back

注意毅该,大括號擴展不是文件名擴展博秫。它會擴展成所有給定的值,而不管是否有對應(yīng)的文件存在眶掌。

$ ls {a,b,c}.txt
ls: 無法訪問'a.txt': 沒有那個文件或目錄
ls: 無法訪問'b.txt': 沒有那個文件或目錄
ls: 無法訪問'c.txt': 沒有那個文件或目錄

上面例子中挡育,即使不存在對應(yīng)的文件,{a,b,c}依然擴展成三個文件名朴爬,導(dǎo)致ls命令報了三個錯誤即寒。

另一個需要注意的地方是,大括號內(nèi)部的逗號前后不能有空格寝殴。否則蒿叠,大括號擴展會失效。

$ echo {1 , 2}
{1 , 2}

上面例子中蚣常,逗號前后有空格市咽,Bash 就會認為這不是大括號擴展,而是三個獨立的參數(shù)抵蚊。

逗號前面可以沒有值施绎,表示擴展的第一項為空。

$ cp a.log{,.bak}

# 等同于
# cp a.log a.log.bak

{start..end} 擴展

大括號擴展有一個簡寫形式{start..end}贞绳,表示擴展成一個連續(xù)序列谷醉。比如,{a..z}可以擴展成26個小寫英文字母冈闭。

$ echo {a..c}
a b c

$ echo d{a..d}g
dag dbg dcg ddg

$ echo {1..4}
1 2 3 4

這個寫法的另一個常見用途俱尼,是直接用于for循環(huán)。

for i in {1..4}
do
  echo $i
done

上面例子會循環(huán)4次萎攒。

這種簡寫形式還可以使用第二個雙點號(start..end..step)遇八,用來指定擴展的步長。

$ echo {0..8..2}
0 2 4 6 8

上面代碼將0擴展到8耍休,每次遞增的長度為2刃永,所以一共輸出5個數(shù)字。

多個簡寫形式連用羊精,會有循環(huán)處理的效果斯够。

$ echo {a..c}{1..3}
a1 a2 a3 b1 b2 b3 c1 c2 c3

變量擴展

Bash 將美元符號$開頭的詞元視為變量,將其擴展成變量值喧锦。

$ echo $SHELL
/bin/bash

變量名除了放在美元符號后面读规,也可以放在${}里面。

$ echo ${SHELL}
/bin/bash

${!string*}${!string@}返回所有匹配給定字符串string的變量名燃少。

$ echo ${!S*}
SECONDS SHELL SHELLOPTS SHLVL SSH_AGENT_PID SSH_AUTH_SOCK

上面例子中掖桦,${!S*}擴展成所有以S開頭的變量名。

子命令擴展

$(...)可以擴展成另一個命令的運行結(jié)果供汛,該命令的所有輸出都會作為返回值。

$ echo $(date)
Tue Jan 28 00:01:13 CST 2020

上面例子中,$(date)返回date命令的運行結(jié)果怔昨。

還有另一種較老的語法雀久,子命令放在反引號之中,也可以擴展成命令的運行結(jié)果趁舀。

$ echo `date`
Tue Jan 28 00:01:13 CST 2020

$(...)可以嵌套赖捌,比如$(ls $(pwd))

算術(shù)擴展

$((...))可以擴展成整數(shù)運算的結(jié)果矮烹。

$ echo $((2 + 2))
4

字符類

[[:class:]]表示一個字符類越庇,擴展成某一類特定字符之中的一個。常用的字符類如下奉狈。

  • [[:alnum:]]:匹配任意英文字母與數(shù)字
  • [[:alpha:]]:匹配任意英文字母
  • [[:blank:]]:空格和 Tab 鍵卤唉。
  • [[:cntrl:]]:ASCII 碼 0-31 的不可打印字符。
  • [[:digit:]]:匹配任意數(shù)字 0-9仁期。
  • [[:graph:]]:A-Z桑驱、a-z、0-9 和標點符號跛蛋。
  • [[:lower:]]:匹配任意小寫字母 a-z熬的。
  • [[:print:]]:ASCII 碼 32-127 的可打印字符。
  • [[:punct:]]:標點符號(除了 A-Z赊级、a-z押框、0-9 的可打印字符)。
  • [[:space:]]:空格理逊、Tab橡伞、LF(10)、VT(11)挡鞍、FF(12)骑歹、CR(13)。
  • [[:upper:]]:匹配任意大寫字母 A-Z墨微。
  • [[:xdigit:]]:16進制字符(A-F道媚、a-f、0-9)翘县。

請看下面的例子最域。

$ echo [[:upper:]]*
A.txt

上面命令輸出所有大寫字母開頭的文件名。

字符類的第一個方括號后面锈麸,可以加上感嘆號!镀脂,表示否定。比如忘伞,[![:digit:]]匹配所有非數(shù)字薄翅。

$ echo [![:digit:]]*

上面命令輸出所有不以數(shù)字開頭的文件名沙兰。

字符類也屬于文件名擴展,如果沒有匹配的文件名翘魄,字符類就會原樣輸出鼎天。

# 不存在以大寫字母開頭的文件
$ echo [[:upper:]]*
[[:upper:]]*

上面例子中,由于沒有可匹配的文件暑竟,字符類就原樣輸出了斋射。

量詞語法

量詞語法用來控制模式匹配的次數(shù)。它只有在 Bash 的extglob參數(shù)打開的情況下才能使用但荤,不過一般是默認打開的罗岖。下面的命令可以查詢。

$ shopt extglob
extglob         on

如果extglob參數(shù)是關(guān)閉的腹躁,可以用下面的命令打開桑包。

$ shopt -s extglob

量詞語法有下面幾個。

  • ?(pattern-list):模式匹配零次或一次潜慎。
  • *(pattern-list):模式匹配零次或多次捡多。
  • +(pattern-list):模式匹配一次或多次。
  • @(pattern-list):只匹配一次模式铐炫。
  • !(pattern-list):匹配給定模式以外的任何內(nèi)容垒手。
$ ls abc?(.)txt
abctxt abc.txt

上面例子中,?(.)匹配零個或一個點倒信。

$ ls abc?(def)
abc abcdef

上面例子中科贬,?(def)匹配零個或一個def

$ ls abc@(.txt|.php)
abc.php abc.txt

上面例子中鳖悠,@(.txt|.php)匹配文件有且只有一個.txt.php后綴名榜掌。

$ ls abc+(.txt)
abc.txt abc.txt.txt

上面例子中,+(.txt)匹配文件有一個或多個.txt后綴名乘综。

$ ls a!(b).txt
a.txt abb.txt ac.txt

上面例子中憎账,!(b)表示匹配單個字母b以外的任意內(nèi)容,所以除了ab.txt以外卡辰,其他文件名都能匹配胞皱。

量詞語法也屬于文件名擴展,如果不存在可匹配的文件九妈,就會原樣輸出反砌。

# 沒有 abc 開頭的文件名
$ ls abc?(def)
ls: 無法訪問'abc?(def)': 沒有那個文件或目錄

上面例子中,由于沒有可匹配的文件萌朱,abc?(def)就原樣輸出宴树,導(dǎo)致ls命令報錯。

引號和 Here 文檔

單引號

Bash 允許字符串放在單引號或雙引號之中晶疼,加以引用酒贬。

單引號用于保留字符的字面含義又憨,各種特殊字符在單引號里面,都會變?yōu)槠胀ㄗ址Ф郑热缧翘枺?code>*)竟块、美元符號($)、反斜杠(\)等耐齐。

$ echo '*'
*

$ echo '$USER'
$USER

$ echo '$((2+2))'
$((2+2))

$ echo '$(echo foo)'
$(echo foo)

上面命令中,單引號使得 Bash 擴展蒋情、變量引用埠况、算術(shù)運算和子命令,都失效了棵癣。如果不使用單引號辕翰,它們都會被 Bash 自動擴展。

雙引號

雙引號比單引號寬松狈谊,大部分特殊字符在雙引號里面喜命,都會失去特殊含義,變成普通字符河劝。

$ echo "*"
*

雙引號還有一個作用壁榕,就是保存原始命令的輸出格式。

# 單行輸出
$ echo $(cal)
一月 2020 日 一 二 三 四 五 六 1 2 3 ... 31

# 原始格式輸出
$ echo "$(cal)"
      一月 2020
日 一 二 三 四 五 六
          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

上面例子中赎瞎,如果$(cal)不放在雙引號之中牌里,echo就會將所有結(jié)果以單行輸出,丟棄了所有原始的格式务甥。

Here 文檔

Here 文檔(here document)是一種輸入多行字符串的方法牡辽,格式如下。

<< token
text
token

它的格式分成開始標記(<< token)和結(jié)束標記(token)敞临。開始標記是兩個小于號 + Here 文檔的名稱态辛,名稱可以隨意取,后面必須是一個換行符挺尿;結(jié)束標記是單獨一行頂格寫的 Here 文檔名稱奏黑,如果不是頂格,結(jié)束標記不起作用票髓。兩者之間就是多行字符串的內(nèi)容攀涵。

Examples of cat <<EOF syntax usage in Bash:

1. Assign multi-line string to a shell variable

$ sql=$(cat <<EOF
SELECT foo, bar FROM db
WHERE foo='baz'
EOF
)

The $sql variable now holds the new-line characters too. You can verify with echo -e "$sql".

2. Pass multi-line string to a file in Bash

$ cat <<EOF > print.sh
#!/bin/bash
echo \$PWD
echo $PWD
EOF

The print.sh file now contains:

#!/bin/bash
echo $PWD
echo /home/user

3. Pass multi-line string to a pipe in Bash

$ cat <<EOF | grep 'b' | tee b.txt
foo
bar
baz
EOF

The b.txt file contains bar and baz lines. The same output is printed to stdout.

Here 字符串

Here 文檔還有一個變體,叫做 Here 字符串(Here string)洽沟,使用三個小于號(<<<)表示以故。

<<< string

它的作用是將字符串通過標準輸入,傳遞給命令裆操。

有些命令直接接受給定的參數(shù)怒详,與通過標準輸入接受參數(shù)炉媒,結(jié)果是不一樣的。所以才有了這個語法昆烁,使得將字符串通過標準輸入傳遞給命令更方便吊骤,比如cat命令只接受標準輸入傳入的字符串。

$ cat <<< 'hi there'
# 等同于
$ echo 'hi there' | cat

上面的第一種語法使用了 Here 字符串静尼,要比第二種語法看上去語義更好白粉,也更簡潔。

$ md5sum <<< 'ddd'
# 等同于
$ echo 'ddd' | md5sum

上面例子中鼠渺,md5sum命令只能接受標準輸入作為參數(shù)鸭巴,不能直接將字符串放在命令后面,會被當作文件名拦盹,即md5sum ddd里面的ddd會被解釋成文件名鹃祖。這時就可以用 Here 字符串,將字符串傳給md5sum命令普舆。

字符串操作

字符串的長度

獲取字符串長度的語法如下恬口。

${#varname}

下面是一個例子。

$ myPath=/home/cam/book/long.file.name
$ echo ${#myPath}
29

大括號{}是必需的沼侣,否則 Bash 會將$#理解成腳本的參數(shù)個數(shù)祖能,將變量名理解成文本。

$ echo $#myvar
0myvar

上面例子中华临,Bash 將$#myvar分開解釋了芯杀。

子字符串

字符串提取子串的語法如下。

${varname:offset:length}

上面語法的含義是返回變量$varname的子字符串雅潭,從位置offset開始(從0開始計算)揭厚,長度為length

$ count=frogfootman
$ echo ${count:4:4}
foot

上面例子返回字符串frogfootman從4號位置開始的長度為4的子字符串foot扶供。

這種語法不能直接操作字符串筛圆,只能通過變量來讀取字符串,并且不會改變原始字符串椿浓。

# 報錯
$ echo ${"hello":2:3}

上面例子中太援,"hello"不是變量名,導(dǎo)致 Bash 報錯扳碍。

如果省略length提岔,則從位置offset開始,一直返回到字符串的結(jié)尾笋敞。

$ count=frogfootman
$ echo ${count:4}
footman

上面例子是返回變量count從4號位置一直到結(jié)尾的子字符串碱蒙。

如果offset為負值,表示從字符串的末尾開始算起。注意赛惩,負數(shù)前面必須有一個空格哀墓, 以防止與${variable:-word}的變量的設(shè)置默認值語法混淆。這時還可以指定length喷兼,length可以是正值篮绰,也可以是負值(負值不能超過offset的長度)。

$ foo="This string is long."
$ echo ${foo: -5}
long.
$ echo ${foo: -5:2}
lo
$ echo ${foo: -5:-2}
lon

上面例子中季惯,offset-5吠各,表示從倒數(shù)第5個字符開始截取,所以返回long.勉抓。如果指定長度length2走孽,則返回lo;如果length-2琳状,表示要排除從字符串末尾開始的2個字符,所以返回lon盒齿。

搜索和替換

Bash 提供字符串搜索和替換的多種方法念逞。

(1)字符串頭部的模式匹配。

以下兩種語法可以檢查字符串開頭边翁,是否匹配給定的模式翎承。如果匹配成功,就刪除匹配的部分符匾,返回剩下的部分叨咖。原始變量不會發(fā)生變化。

# 如果 pattern 匹配變量 variable 的開頭啊胶,
# 刪除最短匹配(非貪婪匹配)的部分甸各,返回剩余部分
${variable#pattern}

# 如果 pattern 匹配變量 variable 的開頭,
# 刪除最長匹配(貪婪匹配)的部分焰坪,返回剩余部分
${variable##pattern}

上面兩種語法會刪除變量字符串開頭的匹配部分(將其替換為空)趣倾,返回剩下的部分。區(qū)別是一個是最短匹配(又稱非貪婪匹配)某饰,另一個是最長匹配(又稱貪婪匹配)儒恋。

匹配模式pattern可以使用*?黔漂、[]等通配符诫尽。

$ myPath=/home/cam/book/long.file.name

$ echo ${myPath#/*/}
cam/book/long.file.name

$ echo ${myPath##/*/}
long.file.name

上面例子中,匹配的模式是/*/炬守,其中*可以匹配任意數(shù)量的字符牧嫉,所以最短匹配是/home/,最長匹配是/home/cam/book/劳较。

下面寫法可以刪除文件路徑的目錄部分驹止,只留下文件名浩聋。

$ path=/home/cam/book/long.file.name

$ echo ${path##*/}
long.file.name

上面例子中,模式*/匹配目錄部分臊恋,所以只返回文件名衣洁。

下面再看一個例子。

$ phone="555-456-1414"
$ echo ${phone#*-}
456-1414
$ echo ${phone##*-}
1414

如果匹配不成功抖仅,則返回原始字符串坊夫。

$ phone="555-456-1414"
$ echo ${phone#444}
555-456-1414

上面例子中,原始字符串里面無法匹配模式444撤卢,所以原樣返回环凿。

如果要將頭部匹配的部分,替換成其他內(nèi)容放吩,采用下面的寫法智听。

# 模式必須出現(xiàn)在字符串的開頭
${variable/#pattern/string}

# 示例
$ foo=JPG.JPG
$ echo ${foo/#JPG/jpg}
jpg.JPG

上面例子中,被替換的JPG必須出現(xiàn)在字符串頭部渡紫,所以返回jpg.JPG到推。

(2)字符串尾部的模式匹配。

以下兩種語法可以檢查字符串結(jié)尾惕澎,是否匹配給定的模式莉测。如果匹配成功,就刪除匹配的部分唧喉,返回剩下的部分捣卤。原始變量不會發(fā)生變化。

# 如果 pattern 匹配變量 variable 的結(jié)尾八孝,
# 刪除最短匹配(非貪婪匹配)的部分董朝,返回剩余部分
${variable%pattern}

# 如果 pattern 匹配變量 variable 的結(jié)尾,
# 刪除最長匹配(貪婪匹配)的部分干跛,返回剩余部分
${variable%%pattern}

上面兩種語法會刪除變量字符串結(jié)尾的匹配部分(將其替換為空)益涧,返回剩下的部分。區(qū)別是一個是最短匹配(又稱非貪婪匹配)驯鳖,另一個是最長匹配(又稱貪婪匹配)闲询。

$ path=/home/cam/book/long.file.name

$ echo ${path%.*}
/home/cam/book/long.file

$ echo ${path%%.*}
/home/cam/book/long

上面例子中,匹配模式是.*浅辙,其中*可以匹配任意數(shù)量的字符扭弧,所以最短匹配是.name,最長匹配是.file.name记舆。

下面寫法可以刪除路徑的文件名部分鸽捻,只留下目錄部分。

$ path=/home/cam/book/long.file.name

$ echo ${path%/*}
/home/cam/book

上面例子中,模式/*匹配文件名部分御蒲,所以只返回目錄部分衣赶。

下面的寫法可以替換文件的后綴名。

$ file=foo.png
$ echo ${file%.png}.jpg
foo.jpg

上面的例子將文件的后綴名厚满,從.png改成了.jpg府瞄。

下面再看一個例子。

$ phone="555-456-1414"
$ echo ${phone%-*}
555-456
$ echo ${phone%%-*}
555

如果匹配不成功碘箍,則返回原始字符串遵馆。

如果要將尾部匹配的部分,替換成其他內(nèi)容丰榴,采用下面的寫法货邓。

# 模式必須出現(xiàn)在字符串的結(jié)尾
${variable/%pattern/string}

# 示例
$ foo=JPG.JPG
$ echo ${foo/%JPG/jpg}
JPG.jpg

上面例子中,被替換的JPG必須出現(xiàn)在字符串尾部四濒,所以返回JPG.jpg换况。

(3)任意位置的模式匹配。

以下兩種語法可以檢查字符串內(nèi)部盗蟆,是否匹配給定的模式复隆。如果匹配成功,就刪除匹配的部分姆涩,換成其他的字符串返回。原始變量不會發(fā)生變化惭每。

# 如果 pattern 匹配變量 variable 的一部分骨饿,
# 最長匹配(貪婪匹配)的那部分被 string 替換,但僅替換第一個匹配
${variable/pattern/string}

# 如果 pattern 匹配變量 variable 的一部分台腥,
# 最長匹配(貪婪匹配)的那部分被 string 替換宏赘,所有匹配都替換
${variable//pattern/string}

上面兩種語法都是最長匹配(貪婪匹配)下的替換,區(qū)別是前一個語法僅僅替換第一個匹配黎侈,后一個語法替換所有匹配察署。

$ path=/home/cam/foo/foo.name

$ echo ${path/foo/bar}
/home/cam/bar/foo.name

$ echo ${path//foo/bar}
/home/cam/bar/bar.name

上面例子中,前一個命令只替換了第一個foo峻汉,后一個命令將兩個foo都替換了贴汪。

下面的例子將分隔符從:換成換行符。

$ echo -e ${PATH//:/'\n'}
/usr/local/bin
/usr/bin
/bin
...

上面例子中休吠,echo命令的-e參數(shù)扳埂,表示將替換后的字符串的\n字符,解釋為換行符瘤礁。

模式部分可以使用通配符阳懂。

$ phone="555-456-1414"
$ echo ${phone/5?4/-}
55-56-1414

上面的例子將5-4替換成-

如果省略了string部分,那么就相當于匹配的部分替換成空字符串岩调,即刪除匹配的部分巷燥。

$ path=/home/cam/foo/foo.name

$ echo ${path/.*/}
/home/cam/foo/foo

上面例子中,第二個斜杠后面的string部分省略了号枕,所以模式.*匹配的部分.name被刪除后返回缰揪。

前面提到過,這個語法還有兩種擴展形式堕澄。

# 模式必須出現(xiàn)在字符串的開頭
${variable/#pattern/string}

# 模式必須出現(xiàn)在字符串的結(jié)尾
${variable/%pattern/string}

改變大小寫

下面的語法可以改變變量的大小寫邀跃。

# 轉(zhuǎn)為大寫
${varname^^}

# 轉(zhuǎn)為小寫
${varname,,}

下面是一個例子。

$ foo=heLLo
$ echo ${foo^^}
HELLO
$ echo ${foo,,}
hello

其它轉(zhuǎn)換大小寫的方法

POSIX standard

tr

$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all

AWK

$ echo "$a" | awk '{print tolower($0)}'
hi all

Non-POSIX

You may run into portability issues with the following examples:

Bash 4.0

$ echo "${a,,}"
hi all

sed

$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛙紫,一起剝皮案震驚了整個濱河市拍屑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坑傅,老刑警劉巖僵驰,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異唁毒,居然都是意外死亡蒜茴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門浆西,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粉私,“玉大人,你說我怎么就攤上這事近零∨岛耍” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵久信,是天一觀的道長窖杀。 經(jīng)常有香客問我,道長裙士,這世上最難降的妖魔是什么入客? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮腿椎,結(jié)果婚禮上桌硫,老公的妹妹穿的比我還像新娘。我一直安慰自己啃炸,他們只是感情好鞍泉,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肮帐,像睡著了一般咖驮。 火紅的嫁衣襯著肌膚如雪边器。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天托修,我揣著相機與錄音忘巧,去河邊找鬼。 笑死睦刃,一個胖子當著我的面吹牛砚嘴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涩拙,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼际长,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兴泥?” 一聲冷哼從身側(cè)響起工育,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搓彻,沒想到半個月后如绸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡旭贬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年怔接,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稀轨。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡扼脐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奋刽,到底是詐尸還是另有隱情瓦侮,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布杨名,位于F島的核電站,受9級特大地震影響猖毫,放射性物質(zhì)發(fā)生泄漏台谍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一吁断、第九天 我趴在偏房一處隱蔽的房頂上張望趁蕊。 院中可真熱鬧,春花似錦仔役、人聲如沸掷伙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽任柜。三九已至卒废,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宙地,已是汗流浹背摔认。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宅粥,地道東北人参袱。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像秽梅,于是被迫代替她去往敵國和親抹蚀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容