ls -lr反向排序結果
==============================
ls ${PATH//:/\ } | grep <searchword>
==============================
echo $RANDOM
==============================
[[ $# -ne 3 ]] && {echo "Usage: ${0##.*/} <param>"; exit 1}
==============================
awk '/'$VAR'/{print $0}' file
==============================
#得到絕對路徑
bin=`dirname "$0"`
bin=`cd "$bin"; pwd`
==============================
echo $[23*34] <==> echo $((23*34))
==============================
echo $[7#23] #7是底,23是在這個底上的數字,因此最終的結果為17
==============================
echo ${!P*} #列出當前變量中,所有以P開頭的變量的名稱
==============================
shell的處理過程:alias la='ls -A'->{1..100}->~admin->$PATH->$(ls)->$((23*34))->rm a*o?[a-zA-Z]*
==============================
#下面這種處理方式等同于for f in "$(ls)",但是可以應對文件名中有空格的情況,而for f in "$(ls)"則不行。
[ $# -eq 0 ] && ls | while read f
do
ll-2.sh "$f"
done
==============================
可以在一行內定義一個函數,寫在shell腳本里可以,還可以直接寫在命令行上,比如:
root@pc1:~#testfunc(){ echo "$# parameters;echo "$@";}
而且,如果你在命令行直接這么定義的,你想查看該函數的內容時,可以用type testfunc,你會看到:
testfunc is a function
testfunc ()
{
echo "$# params";
IFS=;
echo "$*"
}
需要特別注意的是:{和echo之間的那個空格,其他地方有沒有空格無所謂,但是這個空格如果沒有的話,是必然會出錯的;還有個地方是}前面那條命令的;必須有,否則也會有問題;最后,還需要提醒的是,如果你不是寫在一行內,那么}前的;不必有,{后的空格也不必有。
===============================
對$*和$@作些說明:
其實要分四種情況:$*, $@, "$*", "$@"
對于前兩種情況,都等同于$1 $2 $3 ...,如果某個參數內有了空格或者換行(不要覺得不可能,參數中是可以有換行符的,下面就有例子),比如a "b c" d,那么替換后的結果是a b c d,看上去就是四個參數了;
對于"$@",等同于"$1" "$2" "$3" ...,這下就不必擔心參數中有空格或者換行符號了;
對于"$*",還要受到IFS的影響,其實是IFS中的第一個字符的影響,假定IFS中第一個字符是|的話,那么替換后的結果是"$1|$2|$3...";這里對IFS還得作下說明,如果 IFS 為空,則沒有間隔空格。IFS 的默認值是空白、制表符和換行符。如果沒有設置 IFS,則使用空白作為分隔符(僅對默認 IFS 而言),這里特別提到的是,如果你想把參數都串接起來,那么必須得顯示設置IFS=''或者IFS=""或者IFS=即可。
下面給出一個驗證上述描述的超級牛b的例子:
[ian@pinguino ~]$ type testfunc2
testfunc2 is a function
testfunc2 ()
{
echo "$# parameters";
echo Using '$*';
for p in $*;
do
echo "[$p]";
done;
echo Using '"$*"';
for p in "$*";
do
echo "[$p]";
done;
echo Using '$@';
for p in $@;
do
echo "[$p]";
done;
echo Using '"$@"';
for p in "$@";
do
echo "[$p]";
done
}
[ian@pinguino ~]$ IFS="|${IFS}" testfunc2 abc "a bc" "1 2
> 3"
3 parameters
Using $*
[abc]
[a]
[bc]
[1]
[2]
[3]
Using "$*"
[abc|a bc|1 2
3]
Using $@
[abc]
[a]
[bc]
[1]
[2]
[3]
Using "$@"
[abc]
[a bc]
[1 2
3]
看到參數中使用換行符號了吧,哈哈。
===============================
函數返回值return 0~255必須為一個整數,而且范圍只能是0~255,如果大于255,那么會返回$((x%256)),而且不能返回負數,但是允許你寫負數,負數會被強制轉換成整數。
===============================
#!/bin/sh會提供系統默認的shell解釋器,會帶來一些想不到的異常情況,建議都使用#!/bin/bash,在bash中定義函數時function關鍵字是可選的。
===============================
#!/bin/bash
showopts () {
while getopts ":pq:" optname
do
case "$optname" in
"p")
echo "Option $optname is specified"
;;
"q")
echo "Option $optname has value $OPTARG"
;;
"?")
echo "Unknown option $OPTARG"
;;
":")
echo "No argument value for option $OPTARG"
;;
*)
# Should not occur
echo "Unknown error while processing options"
;;
esac
done
return $OPTIND
}
showargs () {
for p in "$@"
do
echo "[$p]"
done
}
optinfo=$(showopts "$@")
argstart=$?
arginfo=$(showargs "${@:$argstart}")
echo "Arguments are:"
echo "$arginfo"
echo "Options are:"
echo "$optinfo"
getopts 命令使用了兩個預先確定的變量。OPTIND 變量開始被設為 1。之后它包含待處理的下一個參數的索引。如果找到一個選項,則 getopts 命令返回 true,因此常見的選項處理范例使用帶 case 語句的 while 循環,本例中就是如此。getopts 的第一個參數是一列要識別的選項字母,在本例中是 p 和 r。選項字母后的冒號 (:) 表示該選項需要一個值;例如,-f 選項可能用于表示文件名,tar 命令中就是如此。此例中的前導冒號告訴 getopts 保持靜默(silent)并抑制正常的錯誤消息,因為此腳本將提供它自己的錯誤處理。
此例中的第二個參數 optname 是一個變量名,該變量將接收找到選項的名稱。如果預期某個選項應該擁有一個值,而且目前存在該值,則會把該值放入 OPTARG 變量中。在靜默模式下,可能出現以下兩種錯誤情況。
1. 如果發現不能識別的選項,則 optname 將包含一個 ? 而 OPTARG 將包含該未知選項。
2. 如果發現一個選項需要值,但是找不到這個值,則 optname 將包含一個 : 而 OPTARG 將包含丟失參數的選項的名稱。
如果不是在靜默模式,則這些錯誤將導致一條診斷錯誤消息而 OPTARG 不會被設置。腳本可能在 optname 中使用 ? 或 : 值來檢測錯誤(也可能處理錯誤)。
此外,getopts ":pq:" optname后面還可以配置上可選的getopts ":pq:" optname "$@"
[ian@pinguino ~]$ ./testargs.sh -p -q qoptval abc "def ghi"
Arguments are:
[abc]
[def ghi]
Options are:
Option p is specified
Option q has value qoptval
[ian@pinguino ~]$ ./testargs.sh -q qoptval -p -r abc "def ghi"
Arguments are:
[abc]
[def ghi]
Options are:
Option q has value qoptval
Option p is specified
Unknown option r
[ian@pinguino ~]$ ./testargs.sh "def ghi"
Arguments are:
[def ghi]
Options are:
===============================
父shell設置的alias是不能傳到子shell中的,但是在shell script中依然可以使用alias,不過要自己手動設定了,然后還要注意在腳本中顯示開啟alias的使用,即 shopt -s expand_aliases;有時候會希望alias能帶參數就好了,其實可以用函數代替即可,在.bashrc中增加:cpdev1(){ [ $# -eq 1 ] && scp $1 yanbin@dev1.asc.cnz.alimama.com: ; },具體啥意思,自己去琢磨吧。
===============================
while [ "${i:-1}" -lt 30 ];do a="-"${a:="-"};((i++));done && echo $a
知識點:while的條件,不新建變量還能正常使用,while是個整體,可以有返回值,可以重定向其輸出
===============================
如果想實現對shell變量的二次解析,那么可以用eval完成,例如:eval cd "\"\$$#\""
===============================
for var in "$@"; <==> for var;
===============================
在shell總一般extglob都是開著的,你可以用shopt查看一下,如果沒開你可以用shopt -s extglob設置一下,在這個選項打開的狀態下,我們可以使用一些擴展的glob選項,在shell中是這么使用的:
?(pattern-list)Matches zero or one occurrence of the given patterns
*(pattern-list)Matches zero or more occurrences of the given patterns
+(pattern-list)Matches one or more occurrences of the given patterns
@(pattern-list)Matches one of the given patterns
!(pattern-list)Matches anything except one of the given patterns
===============================
find . -regextype posix-extended -regex '.*\.(h|cpp)'
===============================
findc(){ [ $# -eq 1 ] && compgen -c | grep --color=auto -i $1; }
===============================
在.bashrc中添加:export PS1='\[\e[1;32;40m\]\u@\h:\w\$ '達到的效果:綠色高亮顯示,且折行時不會在同一行,如果去掉\[和\]則會在同一行折行。
本人目前在用的一個PS1是:export PS1='\[\e[0;35m\]>>>>[\[\e[0;33m\]\t\[\e[0;35m\]][\[\e[0;31m\]\u@\h\[\e[0;35m\]:\[\e[0;33m\]\[\e[0;34m\]\w\[\e[0;35m\]]\n\[\e[1;$((31+3*!$?))m\]\$ \[\e[0;32m\]' ,這個PS1會換行,而且新行的開始部分($或者#)會顯示紅色高亮(上次的命令執行失?。┗蛘咚{色高亮(上次的命令執行正常)。
對于配色,可以參考:
前景 背景 顏色
---------------------------------------
30 40 黑色
31 41 紅色
32 42 綠色
33 43 黃色
34 44 藍色
35 45 紫紅色
36 46 青藍色
37 47 白色
代碼 意義
-------------------------
0 OFF
1 高亮顯示
4 underline
5 閃爍
7 反白顯示
8 不可見
此外,我在ubuntu上設置了上述PS1之后,當我在終端里打開vi再關閉vi之后,發現命令行出現了亂碼,此時輸入reset即可恢復正常,此后再使用vi將不再出現亂碼,不過每次都這么搞一通實在是不爽,不知道在其他發行版上會不會有這個問題。
現在終于解決了這個問題,有兩種方法,一種可以在虛擬終端的title設置中給原先的終端二字前后分別添加一個英文空格即可;另一種方法是重新設置PS1為\[\e]0;\u@\h: \w\a\]\[\e[1;31m\]\u\[\e[1;32m\]@\h\[\e[1;31m\]:\[\e[1;32m\]\w\[\e[1;31m\]\$ \[\e[0m\]
==========================
echo "export LS_COLORS='$LS_COLORS'" >> .bashrc之后打開.bashrc,將di=01;34改為di=01;33即可使得目錄以黃色顯示
==========================
shell腳本調試,可以先設置export PS4='+{$LINENO:${FUNCNAME[0]}} ',再
用sh -x來執行腳本,即可在+號后面打印行號和函數名;使用trap <cmd> DEBUG/ERR/EXIST可以分別在執行每一行前/某個命令返回值不為0時/函數或程序退出時執行cmd;可以在腳本里面的腳本段落前后分別用sh -x和sh +x來使得只有該段落的內容執行sh -x;可以通過變量DEBUG作為開關來統一控制調試與否,當然需要有個函數,比如也叫做DEBUG的話,那這個函數的定義大概為:DEBUG() { [ "$DEBUG" = "true" ] && $@ ; },然后你就可以肆無忌憚的DEBUG echo $a,$b或者在一段落前后分別加上DEBUG set -x和DEBUG set +x來進行控制了;還可以使用類似于Gdb調試的bash調試工具bashdb,官網地址為:http://bashdb.sourceforge.net/;上述總結來自于http://www.ibm.com/developerworks/cn/linux/l-cn-shell-debug/index.html
============================
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "可以讓history顯示出執行的時間
============================
date -d "1970-01-01 0:0:0 UTC `date +%s` sec" +'%F %T' 可以將時間戳轉換為指定的時間表示形式
用date -d @1313418365 +%F\ %T也可以實現將時間戳轉換為指定的時間格式
============================
find . \( -path './rrds*' -o -path './bash*' \) -prune -o -maxdepth 3 -name '*m*' -printf '%f\n'
該命令實現的功能是查找當前目錄下,除了rrds*和bash*文件夾之外的名字中含有m字符的且深度不超過3層的, 將符合上述條件的目錄或文件名打印出來, 不打印全部路徑, 只打印文件名或目錄名. 寫該命令時需要注意的幾點:\(和-path之間以及\)之前都必須有空格;針對path或name定義它們需要符合的pattern時必須要./開頭或者*開頭,因為這里的匹配都是全匹配,而不是包含即可的意思. 對該命令的幾點解釋:find查找文件名或目錄名(其實目錄也是文件)符合pattern所有項, 如果只是中間路徑中含有pattern, 并不能保證該目錄下的所有文件都能和pattern匹配,因為匹配發生在整個路徑的最后,也就是文件名或目錄名上;prune本意為刪除或砍掉的意思,基本上可以理解為和print恰恰相反即可,它們都是action,find命令其實類似于一個復合的if語句, action前面的默認連接是使用-a(即and的意思, 類似于我們常見的command1 && command2 || command3中的&&的作用), 當然也可以顯示的指定-o(即or的意思, 類似于||的作用), 既然談到了and和or,那么自然就有not了,在find命令里,not是!,舉個例子就清楚了:find . ! -name '*.sh'會找到所有不是以.sh結尾的文件, 此外還有就是通過\(和\)能夠把一些復合起來的條件作為一個整體, 因此對于該條命令, 執行過程是這樣的, if ( -path './rrds*' && -path './bash*' ); then -prune else { if (-maxdepth 3 && -name '*m*' ); then -printf '%f\n' fi } fi
此外對于find命令, 最常用的幾個參數是 -type和-name,其實還有-iname(忽略大小寫的匹配), 還有-regex和-iregex,注意-name只是用基本的shell的pattern,即*,?,[]三種, 如果真想用正則來匹配,還是用-regex吧; 此外對于find最神奇的莫過于-exec或者-ok或者xargs了,這里給出兩個例子即可:
find . -name '*my*' -exec rm '{}' \; <==> find . -name '*my*' | xargs rm
find. -name '*my*' -exec cp '{}' ~ \; <==> find . -name '*my*' | xargs -i cp '{}' ~
對于rm這種單參數的命令, find找到的結果直接會塞給rm的; 對于cp這種雙參數的命令, 可以用'{}'這個東西來代表find找到的部分, 但對于xargs中需要注意使用-i參數, 該參數其實和-I參數作用是一樣的,但是特別之處在于當不指定replace-str時, -i這個參數會把{}作為replace-str, 因此使用-i就用經管道|過來的標準輸入去替換{},因此cp命令就生效了.
================
注釋大段shell腳本的方法:
:||:<<\{{
...
{{
這里對here document也多少作些討論:該文檔其實是個臨時文檔,被生成到/tmp目錄下,你用命令bash -c 'lsof -a -p $$ -d0' <<EOF
EOF就可以很清楚的看到這一點;該臨時文檔為交互式shell腳本或者可執行程序提供輸入,最典型的是為cat和ed這樣的命令feed輸入;最典型的應用是在shell中通過cat<<來大段輸出文本, 還有一些比較巧妙的用法,比如為腳本中的函數塞入數據(注意不是為函數塞入參數, 而是當函數中有類似于read這樣的命令時通過here文檔來feed給它), 在比如為變量賦值variable=$(cat <<SETVAR
This variable
runs over multiple lines.
SETVAR)
再比如
vi $TARGETFILE <<\EOF
i
This is line 1 of the example file.
This is line 2 of the example file.
^[
ZZ
EOF
here document自身所特有的幾點包括:
1.用<<-代替<<可以使內容中的leading tabs被忽略,對leading spaces無效
2.用’HERE’, “HERE”, \HERE代替<<后面的HERE,可以使內容中變量不被替換,諸如$HOME
3.如果只希望輸入一行數據,可以用<<<即可,例如cat <<<'hello world' (說到這里, 還真覺得蠻有意思的,一個<表示0號標準輸入; 兩個<<表示here document的臨時性輸入;三個<<<表示單行的here document輸入)
更多詳細例子,可以參考:http://tldp.org/LDP/abs/html/here-docs.html
===============
對于cat這種可以接受標準輸出或者標準輸入流的程序來說, 可以通過一個-來承載送過來的流, 大致可分為通過管道|過來的標準輸出流和通過<送進來的標準輸入流, 通過這樣一個例子就可以看出ls | cat - t.C - - < t.sh <<<'single here document' <<{{
multiple
here
document
{{
結果只是<<發揮作用了, 它們的優先級別是: <<最高, <<<次之, < 排第三, | 排第四
這樣就可以利用該特性為某t.C這樣的文檔添加頁眉和頁腳了:
頁眉: cat - t.C <<<'header'
頁腳: cat t.C - <<<'footer'
=======================================
在腳本中,對于那些腳本依賴的變量,如果沒定義的話就不希望繼續執行腳本,那么可以使用:
set -u
使用了那些你關注的變量的代碼段
set +u
這樣就可以保證腳本在執行過程中沒有發現這些變量時就自動報錯退出
==========================================
按照字符串的長度進行排序:
#! /bin/sh
awk 'BEGIN { FS=RS } { print length, $0}' $1 |
sort -k 1n,1 |
sed 's/^[0-9][0-9]* //' | tee $1 >/de
==========================================
有關shell腳本的第一行,這一行可不是隨便寫的,是有講究的,首先要從這一行中提取出的是一個可執行程序的全路徑,比需要全路徑,在#!后面可以跟空格;其次,會為這個命令要么附加一個選項,要么附加一個參數,記住,有且只能有一個,而且是option和arg二選一,如果有多個參數,其實可以合并,舉個例子,比如ls,可以把-a和-f合并為-af,因此在這條規則下:#!/usr/bin/env sed -f就不能work了,因為sed本身就已經是env的一個arg了,其實在這種情況下,系統會認為'sed -f'整體為一個arg,系統判斷你指定的究竟是一個arg還是一個option的依據就是:是否以-開頭。
=============================================
cd ~1 與cd ~-1代表cd到dirs命令列表中左數/右數第1個目錄(從0開始計數); 注意這種用法并不會與pushd沖突, 因為pushd會對dirs列表進行rotate(一定要好好理解這個單詞的含義, 它相當于把dirs的結果看作是一個round robin的環狀結構, pushd要更改的就是從這個環上的哪個地方找到隊首,然后順時針就可以找到其他的元素了)操作, 舉個例子: 假如dirs的結果為: ~ /usr /etc /tmp四個目錄,那么cd ~1后的結果是/usr /usr /etc /tmp; cd ~-1的結果是/etc /usr /etc /tmp; pushd +1的結果為: /usr /etc /tmp ~; pushd -1的結果為: /etc /tmp ~ /usr
=============================================
查看bash內建命令的help內容,可以用help ulimit,不過這樣得到的信息不全面,全面的信息可以在man builtins里面找到;
========================================
echo -e 'a\tb'和echo $'a\tb'的結果一樣,$'string'形式的字符串會被特殊處理,字符串會被展開,并像c語言那樣將反斜杠及緊跟的字符進行替換,擴展后的結果將被單引號包裹,就好像美元符號一直就不存在一樣,例如$'\n' <=> $'\012' <=> $'\x0a' <=> $'\x0A';$"string"將會使得字符串被翻譯成符合當前locale的語言,如果當前locale是 C 或者 POSIX,美元符號會被忽略,如果字符串被翻譯并替換,替換后的字符串仍被雙引號包裹。
=========================================
command > out.log 2>&1 可以被command &> out.log代替,二者意義一樣,注意&和>之間不能有空格,否則&就會被認為是要把命令放到后臺執行,有關bash一些新增的用法可以參見:http://zh.wikipedia.org/wiki/Bash
============================================
grep -e a -e b file能夠匹配到file中的行內含有a或者b的行
============================================
chvt可以替代Ctrl+Alt+Fn功能鍵;openvt可以在開滿了6個tty之后再新開tty
============================================
在man或者less搜索的時候,用-i來切換大小寫是否敏感(當最左下角顯示為:時進行)
=============================================
export -f可以export函數;unset -f/export -f -n可以取消函數定義;declare -f可以看到當前bash里面所有的函數
==========================================================
函數中可以再定義函數,但卻不是嵌在函數里面的子函數,外部依然可以隨意調用該函數,也就是說和放在外面一樣,只不過看上去能感覺到:這個定義在函數A里面的函數B,應該是專注于為函數A服務的。
==========================================================
在bash里fork子shell
#!/bin/bash
if [ "$PROC_PID" != "$PPID" ]; then
export PROC_PID=$$
var="mype"
echo "initial $var"
declare -r var
export var
$0 & # child process
else
echo "before $var"
var="netty5"
echo "after $var"
fi
=================================================================================================
在腳本中$@代表當前shell腳本執行時的所有參數或者代表傳遞到當前函數內部的所有參數,通過shift命令,可以改變$@的內容,但是$0始終代表當前進程的命令名字,而不是函數名字
=================================================================================================
getopts函數(bash builtin)的功能還是很弱的,比如要解析pq:,那么必須得這么寫命令才行:<your_command> -p -q test arg1 arg2 ...;參數之間不能斷開,而且還得必須緊跟在command的后面,當然,getopts是解析$@,如果你用shift處理后的$@能滿足$1開始就是option,那么也行。
======================================================
在linux下作各種進制的轉化,有兩種方法比較好用:
printf "%x\n" 2342 #該方法和c語言中的printf沒什么區別
echo 'obase=16; 2342' | bc #該方法很強大, 可以轉化為任意進制, 比如printf不能做到的2進制轉化
============================================================
echo $content | while read line;
do
...
done
上面這段代碼有3個問題:
1. echo時應該給$content添加雙引號,否則content中的空格換行tab之類的東西就都丟了;
2. 用管道會導致while是在一個新的子shell里, 導致在while中用的變量其實是新定義的, 而不是context中的;
3. read會忽略前導空格, 因為read會使用IFS的第一個字符作為分割符號, 把當前line分割為若干個word, 你用read word1 word2 word3會讀取到各個單詞, 默認IFS的第一個字符是空格, 因此假定當前line為' a'的話, 那么會被切割為3部分(因為有2個空格), 最后組裝的時候, 會忽略掉空單詞, 因此最后就只剩下a了.
正確的做法是:
IFS=
while read line;
do
...
done < <(echo "$content")
這里提一下<()和>()的用法, 這兩個東西都是命名管道(但這里是沒有名字的, 實則它們是借助于某一個fd來完成的), 相當于你先mkfifo了一個命令管道xxx, 然后你echo "$content" > xxx, 同時你的read函數已經在xxx的另一端候著了while read line; do ... done < xxx. 用<()和>()省略了建立xxx的過程.
==============================================================================
tr 'a-z' 'A-Z' < t1.txt > t1.txt像這種語句,都會把t1.txt清空,其實是bash在這里做了手腳,我們都知道在bash中ls *時,其實bash會先把*擴展為當前所有的文件,然后再讓ls去顯示,這里也差不多,bash發現>時,會先把該文件清空,然后再交給tr去處理,所以tr啥都不用做就完成了,而此時t1.txt就變成空文件了,要想避免這種情況發生,可以tr 'a-z' 'A-Z' < t1.txt >> t1.txt,但這樣會保留t1.txt之前的內容,現在借助于<>,搞出個簡單的方法:tr 'a-z' 'A-Z' < t1.txt 1<> t1.txt,這里1<>代表通過fd為1的文件進行read and write,這樣就繞過了bash的提前解析,因此t1.txt中的內容也被成功替換掉了。但要注意的是,同時從一個文件既讀取又寫入,而且是以管道這種流的形式來搞(正因為是流的形式[讀一點寫一點],所以就不會全部讀到內存中,然后再處理,再把處理后的結果從內存中dump到輸出文件),所以這種只對那種本位替換有效果,例如tr或者sed這種,其實說到這里,主要是為了引出<>這個符號的用法,并讓大家知道bash會先把>給解析了,其他的都不重要。
strace是個太好太好的命令,例如strace sed -i 's/a/A/g' t1.cpp即可看到sed是使用了臨時文件進行替換的。
================================================
#!/bin/bash
mput() {
eval "__map_$1"__"$2"='$3'
}
mget() {
eval echo '${__map_'"$1__$2"'}'
}
mgetall() {
for i in $(eval echo '${!__map_'"$1"'__*}'); do
echo -n "${i#__map_$1__*}:"
eval echo '${'"$i"'}';
done
}
mput capitals France Paris
mput capitals Spain Madrid
echo "$(mget capitals France)"
mgetall capitals
=================================================
func () {
local unset_x=false
[[ "$(echo $-)" =~ x ]] || unset_x=true
[ "false" == "$unset_x" ] && set +x
#procedure here
[ "false" == "$unset_x" ] && set -x
}
=================================================
ulimit -c unlimited
export PS4='+{$LINENO($(date +"%F %T")):${FUNCNAME[0]}} '
exec 1>${0%.*}.log
exec 2>${0%.*}.err
mkdir -p .tmp
export TMPDIR=.tmp
set -x
====================================================
__created_tmp_files__=""
delete_tmp_files() {
if [ -n "$__created_tmp_files__" ]; then
rm -f $__created_tmp_files__
fi
}
trap delete_tmp_files EXIT
create_tmp_file() {
local unset_x=false
[[ "$(echo $-)" =~ x ]] || unset_x=true
[ "false" == "$unset_x" ] && set +x
if [ -z "$(eval "echo $"$1)" ]; then
eval "$1=.tmp/.__${0##*/}_${LINENO}_$1_${RANDOM}__.tmp"
rm -f $(eval "echo $"$1)
__created_tmp_files__="$__created_tmp_files__ $(eval "echo $"$1)"
fi
[ "false" == "$unset_x" ] && set -x
}
===================================================
awk '
{
if (NF>5 || ("noresource" != $NF && "zero" != $NF && "part" != $NF && "all" != $NF)) {
print $0 > "/dev/stderr"
} else if ($4 ~ /^http/) {
print $1, (4==$2 ? "y" : "n"), $4, ($5=="all" ? "y" : "n")
} else {
print $1, (4==$2 ? "y" : "n"), "none", ($4=="all" ? "y" : "n")
}
}' $2 | awk '
BEGIN {
pv=0;
}
{
if (FILENAME==ARGV[1]) {
sitepv[$1]=++pv;
} else {
r[sitepv[$1]]=$0;
}
}
END {
for (i in r) {
print i, r[i];
}
}' $1 - | sort -n -k 1 | awk '
{
for (i=2; i<NF; ++i) {
printf "%s ", $i
}
printf "%s\n", $NF
}'
==========================================
awk -v max_qps=$max_qps -v max_qps_time="$max_qps_time" -v bad_request_num=$bad_request_num '
BEGIN {
total_request_num=0;
total_sum=0;
max_value=0;
max_value_time=0;
min_value=0;
min_value_time=0;
cur_value=0;
level8_threshold=(0 != l8 ? l8 : 3000);
level7_threshold=(0 != l7 ? l7 : 1500);
level6_threshold=(0 != l6 ? l6 : 1000);
level5_threshold=(0 != l5 ? l5 : 500);
level4_threshold=(0 != l4 ? l4 : 200);
level3_threshold=(0 != l3 ? l3 : 100);
level2_threshold=(0 != l2 ? l2 : 50);
level1_threshold=(0 != l1 ? l1 : 30);
gt_level8_threshold_num=0;
gt_level7_threshold_num=0;
gt_level6_threshold_num=0;
gt_level5_threshold_num=0;
gt_level4_threshold_num=0;
gt_level3_threshold_num=0;
gt_level2_threshold_num=0;
gt_level1_threshold_num=0;
le_level1_threshold_num=0;
}
1 == NR {
cur_value=int(substr($14,4));
max_value=min_value=cur_value;
max_value_time=min_value_time=int(substr($1,4));
++total_request_num;
total_sum += cur_value;
next;
}
{
cur_value=int(substr($14,4));
if (cur_value > max_value) {
max_value=cur_value;
max_value_time=int(substr($1,4));
} else if (cur_value < min_value) {
min_value=cur_value;
min_value_time=int(substr($1,4));
}
if (cur_value > level8_threshold) {
++gt_level8_threshold_num;
} else if (cur_value > level7_threshold) {
++gt_level7_threshold_num;
} else if (cur_value > level6_threshold) {
++gt_level6_threshold_num;
} else if (cur_value > level5_threshold) {
++gt_level5_threshold_num;
} else if (cur_value > level4_threshold) {
++gt_level4_threshold_num;
} else if (cur_value > level3_threshold) {
++gt_level3_threshold_num;
} else if (cur_value > level2_threshold) {
++gt_level2_threshold_num;
} else if (cur_value > level1_threshold) {
++gt_level1_threshold_num;
} else {
++le_level1_threshold_num;
}
++total_request_num;
total_sum += cur_value;
}
END {
gt_level7_threshold_num += gt_level8_threshold_num;
gt_level6_threshold_num += gt_level7_threshold_num;
gt_level5_threshold_num += gt_level6_threshold_num;
gt_level4_threshold_num += gt_level5_threshold_num;
gt_level3_threshold_num += gt_level4_threshold_num;
gt_level2_threshold_num += gt_level3_threshold_num;
gt_level1_threshold_num += gt_level2_threshold_num;
print total_request_num;
printf "%d(%.2f%%)\n", bad_request_num, bad_request_num * 100 / total_request_num;
printf "%d(occur at: %s)\n", max_qps, max_qps_time;
cmd="date -d @"max_value_time" +\"%F %T\""; cmd | getline max_value_time_str; close(cmd);
printf "%d ms(occur at: %s)\n", max_value, max_value_time_str;
# printf "%d ms(occur at: %s)\n", min_value, strftime("%F %T", min_value_time);
printf "%.2f ms\n", total_sum / total_request_num;
print gt_level8_threshold_num;
print gt_level7_threshold_num;
print gt_level6_threshold_num;
print gt_level5_threshold_num;
print gt_level4_threshold_num;
print gt_level3_threshold_num;
print gt_level2_threshold_num;
print gt_level1_threshold_num;
print le_level1_threshold_num;
}' $tmp_analyse_file
=================================================================
awk -v threshold=1000 -v debug=n '
BEGIN {
}
{
if (FILENAME==ARGV[1]) {
checked_css[$1]="y";
} else if ("y" != checked_css[$1]) {
if (n[$1] < threshold) {
css[$1, n[$1]++] = $2;
} else {
k = int((rand() * threshold) % threshold);
if("y"==debug)print "[DEBUG]over threshold:", $1, "k=", k, "old item:", css[$1, k], "new item:", $2 > "/dev/stderr";
css[$1, k] = $2;
}
} else {
if("y"==debug)print "[DEBUG]existed css:",$1 > "/dev/stderr";
}
}
END {
for (i in n) {
if (n[i] >= threshold) {
printf "%s\t", i;
for (j=0; j< threshold; ++j) {
printf "%s ", css[i, j];
}
printf "\n";
}
}
}' css_ok.txt -
========================================================================
awk 'BEGIN {
OFS=",";
array[1,2]=3; array[2,3]=5; array[3,4]=8;
for (comb in array) {
split(comb,sep,SUBSEP);
print sep[1], sep[2], array[sep[1],sep[2]];
}
}'
========================================================================
$ awk 'BEGIN{a["one"]=1;a["two"]=2;a["three"]; if("one2" in a)print a["one"]; for(i in a) print i, a[i]}'
three
one 1
two 2
=========================================================================
$ awk 'BEGIN{a=3;b=4; print a,b; print a, b; print a b;print a b;}'
3 4
3 4
34
34
==========================================================================
$ awk -F$'\t' 'BEGIN{OFS="\t"}{if($3 ~ /ECSHOP/)print $1,$2;}' t3.4 #否則會用空格來分隔fields,print $0不受OFS的影響
==========================================================================
bash里面的大小寫轉換:
$ a="abCdEF"
$ echo ${a^} #process the first character
AbCdEF
$ echo ${a^^} #process all characters
ABCDEF
$ echo ${a,} #process the first character
abCdEF
$ echo ${a,,} #process all characters
abcdef
bash里的substr:
$ a="abCdEF"
$ echo ${a:1}
bCdEF
$ echo ${a:2:1}
C
bash里的數組操作:
a=() #empty array
a=(one two three) #three elements in array, with subscripts: 0 1 2
${#a[*]} #length of array
${a[*]} #all elements of array
${!a[*]} #all subscripts of array
${a[*]:2:1} #extract elements, offset index is 2, and length is 1
${a[*]:2} #extract elements, offset index is 2, and length is big enough to fetch all residue elements
${a[*]: -1} #extract last element, note that the space between : and -, by the way, ${@:3:2} will extract $3 and $4
unset a[0] #destory the element with 0 subscript
unset a[*] #destory array
bash里的associated數組(即map):
這個特性需要bash的版本>=4
declare -A a
$ a[one]=1
$ a["two"]=2
$ a[3]=three
$ echo ${!a[*]}
one two 3
bash里數組元素是否存在的檢測方法:
$ ${a[two]+:} false && echo ok || echo fail #${var+XX} will be XX if var is set, or empty; so ${a[two]+:} false will be ': false'
ok
$ [[ ${a[two]+set} ]] && echo ok || echo fail #${a[two]+set} will be 'set', so [[ set ]] is true;
ok
$ ${a[2]+:} false && echo ok || echo fail #${a[2]+:} false will be ' false'
fail
更多詳情可參見:http://mywiki.wooledge.org/BashFAQ/083
bash里的復合命令(Compound Commands):
(( expression ))用于檢測數值運算(ARITHMETIC EVALUATION),例如
$ (( 3+3 )) && echo ok || echo fail
ok
$ (( 3-3 )) && echo ok || echo fail
fail
也包括數值類的比較運算符:< > >= !=等
[[ expression ]]用于檢測字符串相關的表達式,例如 [[ hello ]], [[ -f test.dat ]], 也可用于帶BashPattern的匹配,例如[[ abc == ab* ]],或者正則字符串匹配[[ abc =~ ^ab ]]
[ expression ]不屬于bash,因為[其實是一個外部命令,和ls一樣
bash里忽略大小寫的字符串比較:
$ shopt -s nocasematch
$ [[ aBc == abc ]] && echo ok || echo fail
ok
set -o會列出控制bash的所有選項,其實還有一些其他的選項需要通過shopt來控制,shopt會列出全部的選項
===========================================================
a2=99
a1=88
b=a2
echo ${!a*} #list all shell variables that start with a
a1 a2
echo ${!b} #this express is equal to: eval 'echo $'$b
99
================================================================
!net #從歷史命令里搜索以net開頭的最近使用的一條命令
!?net #從歷史命令里搜索包含net的最近使用的一條命令
!:0 #上一條命令的command(類似于argv[0])
!:^ #上一條命令的第一個參數
!:$ #上一條命令的最后一個參數(效果等同于Alt+. ,不過Alt+.按n次,是會到倒數第n條命令里取得最后一個參數的)
!:* #上一條命令的所有參數(效果等同于 !:^-$)
!:2-4 #上一條命令的第2個到第4個參數
!:2* #上一條命令從第2個參數開始(包括第2個參數)以后的參數(效果等同于!:2-$)
!:2- #上一條命令從第2個參數開始(包括第2個參數)到 倒數第2個參數,即省略掉最后一個參數
^ll^md5sum #從上一條里把第一次出現的ll替換為md5sum后重新執行
!!:gs/ll/md5sum #從上一條命令里把所有出現的ll都替換為md5sum(這里的語法類似于sed,/也可以用其他符號例如@來代替,g表示多次匹配)
!! #重新執行上一條命令(效果等同于Ctrl-p)