文本處理
less -SN # -N顯示行號,-S整齊,變?yōu)橐恍?grep -w #精準匹配
grep '^#' #匹配以#開頭的行。正則表達式
grep -v #排除匹配到的
alias del=rm #給rm起個別名del,del同樣發(fā)揮rm的作用
tr ';' '\t' # tr命令,把分號換成\t
sed 's/;/\t/g' #與上等效
cut -f1 gtf | sort | uniq -c | sort -k1,1 -r # uniq去重復的行,并計數(shù)。去重后再sort排序,按第一列的數(shù)值進行由大到小的排序,去除r參數(shù),由小到大
history | awk '{print $2}' | sort | uniq -c | sort -n -k1 # sort -n 按照數(shù)值的大小排序,按照第一列排序 -k1。
awk '{print $1}' tmp | paste -s -d + |bc #bc算術表達式,tmp的第一列為幾行數(shù)值,awk把第一列抽取出來,paste -s把第一列的數(shù)值變?yōu)橐恍校?d設置以+分割,最后變?yōu)?+2+3的形式,再通過bc求和。需要以*分割的話,設置-d '*'
awk '{if($3=="gene")print}' gtf | wc
Shell腳本編程
cat /proc/cpuinfo | grep processor #查看服務器有多少個線程 / 核
free -g #查看服務器的內存
df -h #查看服務器的硬盤 / 存儲
for i in {20..23};do echo SRR10395${i}_1_val_1.fq.gz ;done #注意i的大括號,因為后面接了字符
for bam in *bam;do echo ${bam%%.*} ; done # bam文件格式為SRR1039510.bowtie.bam,一個%.*刪除了后一個.后的內容,兩個%即%%.*輸出的為SRR1039510
samtools idxstats SRR1039508.hisat.bam | awk -F '\t' '{s+=$3}END{print s}' # s+=$3,把以\t分隔開后的第3列的數(shù)字加起來求和并輸出
export total_reads = $(samtools idxstats $bam | awk -F '\t' '{s+=$3}END{print s}' ) #賦值給total_reads。export后,可以對子
shell同樣起作用
Shell 十三問 學習筆記
shell and Carriage 關系
Shell會依據(jù)IFS(Internal Field Seperator) 將 command line 所輸入的文字給拆解為字段(word). 然后在針對特殊的字符(meta)先做處理,最后在重組整行 command line。
分隔符號IFS是用來拆解command line中每一個詞 (word) 用的, 因為shell command line是按詞來處理的。 而CR(Carriage Return, 由Enter鍵產生)則是用來結束command line用的,這也是為何我們敲Enter鍵, 命令就會跑的原因。
""(雙引號) 與''(單引號) 差在哪?
hard quote:''(單引號),凡在 hard quote 中的所有 meta 均被關閉;
soft quote:""(雙引號),凡在 soft quote 中大部分 meta 都會被關閉,但某些會保留 (如 $);
escape: \ (反斜杠),只有在緊接在 escape(跳脫字符) 之后的單一 meta 才被關閉;
$ A=`B > C > ' $ echo "$A" B C
$ A="B > C > " $ echo $A B C
$ A=B\ > C\ > $ echo $A BC
soft quote 跟 hard quote 的不同,主要是對于某些 meta 的關閉與否,以 $ 來做說明:
$ A=B\ C
$ echo "$A"
B C
$ echo '$A'
$A
awk '{print $0}'
上面的 hard quote 應好理解,就是將原來的 {$} 這幾個 shell meta 關閉, 避免掉在 shell 中遭到處理,而完整的成為 awk 的參數(shù)中 command meta。
awk "{print \$0}" 1.txt
awk \{print \$0\} 1.txt #與上是等效的,注意`\`關閉了$ 字符
var=value 在 export 前后的差在哪?
所謂的變量,就是利用一個固定的"名稱"(name), 來存取一段可以變化的"值"(value)。
設定變量時:
- 等號左右兩邊不能使用分隔符號(IFS)
name=value,也應避免使用shell的保留元字符(meta charactor); - 變量的名稱(name)的首字符不能是數(shù)字(number);
- 變量的名稱(name)不能使用$符號。
shell 之所以強大,其中的一個因素是它可以在命令行中對變量作 替換(substitution)處理。 在命令行中使用者可以使用$符號加上變量名稱(除了用=定義變量名稱之外), 將變量值給替換出來,然后再重新組建命令行。
A=BCD
A=${A}E
上例中,我們使用{}將變量名稱范圍給明確定義出來, 如此一來, 我們就可以將A的變量值從BCD給擴充為BCDE。
嚴格來說,我們在當前shell中所定義的變量,均屬于 "本地變量"(local variable), 只有經過export命令的 "輸出"處理,才能成為"環(huán)境變量"(environment variable):
$ A=B
$ export A
或者$ export A=B
經過export輸出處理之后,變量A就能成為一個環(huán)境變量 供其后的命令使用。
exec 跟 source 差在哪?
了解一下進程 (process) 的概念
首先,我們所執(zhí)行的任何程序,都是父進程 (parent process) 產生的一個 子進程 (child process), 子進程在結束后,將返回到父進程去。 此現(xiàn)象在 Linux 中被稱為fork。當子進程被產生的時候,將會從父進程那里獲得一定的資源分配、及 (更重要的是) 繼承父進程的環(huán)境。
所謂環(huán)境變量其實就是那些會傳給子進程的變量。 簡單而言, "遺傳性" 就是區(qū)分本地變量與環(huán)境變量的決定性指標。 然而,從遺傳的角度來看,我們不難發(fā)現(xiàn)環(huán)境變量的另一個重要特征: 環(huán)境變量只能從父進程到子進程單向傳遞 換句話說:在子進程中環(huán)境如何變更,均不會影響父進程的環(huán)境。
所謂 shell script 講起來很簡單,就是將你平時在 shell prompt 輸入的多行 command line, 依序輸入到一個文件文件而已。
再結合以上兩個概念 (process + script),那應該不難理解如下的這句話的意思了: 正常來說,當我們執(zhí)行一個 shell script 時,其實是先產生一個 sub-shell 的子進程, 然后 sub-shell 再去產生命令行的子進程。
cd/etc/aa/bb/cc 可以執(zhí)行 但是把這條命令放入 shell 腳本后,shell 腳本不執(zhí)行!腳本運行完后并沒有換目錄 這是什么原因?
答案:因為,我們一般跑的 shell script 是用 sub-shell 去執(zhí)行的。 從 process 的概念來看,是 parent process 產生一個 child process 去執(zhí)行, 當 child 結束后,返回 parent, 但 parent 的環(huán)境是不會因 child 的改變而改變的。 所謂的環(huán)境變量元數(shù)很多,如 effective id(euid),variable, working dir 等等... 其中的 working dir(PWD)正是樓主的疑問所在:當用sub?shell來跑script的話,sub?shell的
pwd 會因為 cd 而變更, 但返回 primary shell 時,$PWD 是不會變更的。
所謂source命令,就是讓 script 在當前 shell 內執(zhí)行、 而不是產生一個 sub-shell 來執(zhí)行。 由于所有執(zhí)行結果均在當前 shell 內執(zhí)行、而不是產生一個 sub-shell 來執(zhí)行。
$ source ./my_script.sh
() 與 {} 差在哪?
"命令群組"(command group) 的概念:將許多命令集中處理。
在 shell command line中,()與 {}這兩個符號都可以將多個命令當作群組處理, 技術細節(jié)上的差異:
() 將command group置于sub-shell(子shell) 中去執(zhí)行,也稱 nested sub-shell。
{} 則是在同一個shell內完成,也稱non-named command group。
要是在 command group中扯上變量及其他環(huán)境的修改, 我們可以根據(jù)不同的需求來使用()或{}。 通常而言, 若所作的修改是臨時的,且不想影響原有或以后的設定, 那我們就使用(); 反之,則用{}。
(())與()還有${}差在哪?
$()與(反引號)都可以用來做命令替換(command substitution)的,完成 或者$()里面的 命令,將其結果替換出來,再重組命令行。
我更喜歡用$()
先將command3替換出來給command2處理, 然后再將command2的處理結果,給command1來處理。
command1 $(commmand2 $(command3))
command1 `command2 \`command3\` ` #中間用 \ 轉義 `
不過,()并不是沒有弊端的...首先,``基本上可用在所有的unixshell中使用,若寫成shellscript,其移植性比較高。而()并不是每一種shell都能使用,我只能說, 若你用bash2的話,肯定沒問題... _
#是去掉左邊(在鍵盤上#在$的左邊)
%是去掉右邊(在鍵盤上%在$的右邊)
單個符號是最小匹配
兩個符號是最大匹配
定義一個變量file為:
file=/dir1/dir2/dir3/my.file.txt
我們可以用${}分別替換獲得不同的值:
${file#*/} #拿掉第一個/及其左邊的字符串,其值為:dir1/dir2/dir3/my.file.txt
${file#*.} #拿掉第一個.及其左邊的字符串,其值為:file.txt
${file##*/} #其值為:my.file.txt # 拿掉最后一個/及其左邊的字符串,其結果為: my.file.txt
${file##*.} #其值為:txt # 拿掉最后一個.及其左邊的字符串,其結果為: txt
${file%/*} #其值為:/dir1/dir2/dir3 # 拿掉最后一個/及其右邊的字符串,其結果為: /dir1/dir2/dir3。
${file%.*} #其值為:/dir1/dir2/dir3/my.file # 拿掉最后一個.及其右邊的字符串,其結果為: /dir1/dir2/dir3/my.file。
${file%%/*} #其值為:其值為空。 # 拿掉第一個/及其右邊的字符串,其結果為: 空串。
${file%%.*} #其值為:/dir1/dir2/dir3/my。# 拿掉第一個.及其右邊的字符串,其結果為: /dir1/dir2/dir3/my。
shell 字符串取子串
${file:0:5} #提取最左邊的5個字符:/dir1
${file:5:5} #提取第5個字符及其右邊的5個字符:/dir2
shell 字符串取子串的格式:${s:pos:length}, 取字符串 s 的子串:從 pos 位置開始的字符(包括該字符)的長度為 length 的的子串; 其中pos為子串的首字符,在 s 中位置; length為子串的長度。
shell 字符串變量值的替換
${file/dir/path} #將第一個dir替換為path:/path1/dir2/dir3/my.file.txt
${file//dir/path} #將全部的dir替換為path:/path1/path2/path3/my.file.txt
shell 字符串變量值的替換格式:
- 首次替換: ${s/src_pattern/dst_pattern} 將字符串s中的第一個src_pattern替換為dst_pattern。
- 全部替換: ${s//src_pattern/dst_pattern} 將字符串s中的所有出現(xiàn)的src_pattern替換為dst_pattern.
計算 shell 字符串變量的長度:${#var}
${#file} #其值為27, 因為/dir1/dir2/dir3/my.file.txt剛好為27個字符
數(shù)組(array)的處理方法
一般而言, A="a b c def" 這樣的變量只是將
$A替換為一個字符串, 但是改為 A=(a b c def), 則是將$A定義為數(shù)組
${A[@]} #方法一
${A[*]} #方法二
以上兩種方法均可以得到:a b c def, 即數(shù)組的全部元素。
訪問數(shù)組的成員
${A[0]}
得到數(shù)組A的第一個元素
數(shù)組的 length
${#A[@]} #方法一,前面加個#
${#A[*]} #方法二
數(shù)組元素的重新賦值
A[3]=xyz #將數(shù)組A的第四個元素重新定義為 xyz
$(())是用來作整數(shù)運算的
在bash中, $(())的整數(shù)運算符號大致有這些:
- +- * / #分別為"加、減、乘、除"。
- % #余數(shù)運算,(模數(shù)運算)
- & | ^ ! #分別為"AND、OR、XOR、NOT"運算。
$ a=5; b=7; c=2;
$ echo $(( a + b * c ))
19
$ echo $(( (a + b)/c ))
6
$ echo $(( (a * b) % c ))
1
&& 與 || 差在哪?
&& 與 || 都是用來 "組建" 多個 command line 用的;
command1 && command2 # command2 只有在 command1 的 RV 為 0(true) 的條件下執(zhí)行。
command1 || command2 # command2 只有在 command1 的 RV 為非 0(false) 的條件下執(zhí)行。
[ -n string ]是測試 string 長度大于 0, 則為 true。
當 $A 被賦值時,在看看其是否小于 100,否則輸出 too big!
$ A=123
$ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!'
$ too big!
若取消 A,照理說,應該不會輸出文字啊,(因為第一個條件不成立)。
$ unset A
$ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!'
$ too big!
但還是可以得到上面的結果, 解決方法如下
方法1 sub-shell
$ unset A
$ [ -n "$A" ] && ( [ "$A" -lt 100 ] || echo 'too big!' ) #利用 ()
方法2 command group
$ unset A
$ [ -n "$A" ] && { [ "$A" -lt 100 ] || echo 'too big!'} #利用 {}
你要 if 還是 case 呢?
cmd1 && {
cmd2
cmd3
;
} || {
cmd4
cmd5
}
若 cmd1的return value為true的話, 然后執(zhí)行cmd2與cmd3, 否則執(zhí)行cmd4與cmd5.
與上等效
if cmd1
then
cmd2
cmd3
else
cmd4
cmd5
fi
只要if后面的command line返回true的return value (我們常用test命令返回的return value), 然則就執(zhí)行then后面的命令,否則,執(zhí)行else之后的命令, fi則是用來結束判斷式的keyword。
if cmd1; then
cmd2;
elif cmd3; then
cmd4
else
cmd5
fi
若cmd1為true,然則執(zhí)行cmd2; 否則在測試cmd3,若為true則執(zhí)行cmd4; 倘若cmd1與cmd3均不成立,那就執(zhí)行cmd5
for what? while 與 until 差在哪?
for loop
for loop 是從一個清單列表中讀進變量的值, 并依次的循環(huán)執(zhí)行do到done之間的命令行。 例:
for var in one two three four five
do
echo -----------------
echo '$var is '$var
echo
done
上例的執(zhí)行結果將會是:
- for會定義一個叫var的變量,其值依次是one two three four five。
- 因為有5個變量值,因此,do與done之間的命令行會被循環(huán)執(zhí)行5次。
- 每次循環(huán)均用echo產生3個句子。而第二行中不在hard quote之內的$var會被替換。
- 當最后一個變量值處理完畢,循環(huán)結束。
在for loop中,變量值的多寡,決定循環(huán)的次數(shù)
對于一些“累計變化”的項目(整數(shù)的加減),for 也能處理:
for ((i = 1; i <= 10; i++))
do
echo "num is $i"
done
while loop
除了for loop, 上面的例子, 我們也可改用while loop來做到:
num=1
while [ "$num" -le 10 ]; do
echo "num is $num"
num=$(($num + 1))
done
分析上例:
- 在while之前,定義變量num=1.
- 然后測試(test)$num是否小于或等于10.
- 結果為true,于是執(zhí)行echo并將num的值加1.
- 再作第二輪測試,此時num的值為1+1=2,依然小于或等于10,因此,為true,循環(huán)繼續(xù)。
- 直到num為10+1=11時,測試才會失敗...于是結束循環(huán)。
while loop的原理與for loop稍有不同: 它不是逐次處理清單中的變量值, 而是取決于while 后面的命令行的return value:
- 若為true, 則執(zhí)行do與done之間的命令, 然后重新判斷while后的return value。
- 若為false,則不再執(zhí)行do與done之間的命令而結束循環(huán)。
until loop
until loop與while相反, until是在return value 為false時進入循環(huán),否則,結束。 因此,前面的例子也可以輕松的用until來寫:
num=1
until [ ! "$num" -le 10 ]; do
echo "num is $num"
num=$(($num + 1))
done
或者
num=1
until [ "$num" -gt 10 ]; do
echo "num is $num"
num=$(($num + 1))
done
if [ 1 -ne 1 ];then
...
fi
-eq:等于
-ne:不等于
-le:小于等于
-ge:大于等于
-lt:小于
-gt:大于
shell loop 中的 break 與 continue
break用來中斷循環(huán),也就是強迫結束循環(huán)。
而continue則與break相反:強迫進入下一次循環(huán)動作
可簡單的看成: 在continue與done之間的句子略過而返回到循環(huán)的頂端