linux bash shell 三言兩語
2017/11/14
linux bash shell的使用博大精深,,本人梳理基礎知識,整理一下簡單的用法,細節請根據需求自行研究。 1. 計算 # echo $((1+2)) 3 # echo $((1+2+3)) 6 # echo 3+2+5 |bc 10 2. if的用法 if [ $i -eq 0 ]; then xxx else xxx fi 注意下面這2種判斷方式: 1)test, && 和 || 的用法 [root@tvm01 ~]# a=3 [root@tvm01 ~]# test $a -eq 3 && echo 'a' || echo 'b' a [root@tvm01 ~]# test $a -eq 4 && echo 'a' || echo 'b' b [root@tvm01 ~]# test $a -eq 4 && echo 'a' || echo 'b' && echo 'c' b c [root@tvm01 ~]# test $a -eq 3 && echo 'a' || echo 'b' && echo 'c' a c 2)不加if,也不用 test [ -d '/tmp/aaa' ] || mkdir -p /tmp/aaa 3)整數比較: -eq 等於,如:if [ "$a" -eq "$b" ] -ne 不等於,如:if [ "$a" -ne "$b" ] -gt 大於,如:if [ "$a" -gt "$b" ] -ge 大於等於,如:if [ "$a" -ge "$b" ] -lt 小於,如:if [ "$a" -lt "$b" ] -le 小於等於,如:if [ "$a" -le "$b" ] < 小於(需要雙括號),如:(("$a" < "$b")) <= 小於等於(需要雙括號),如:(("$a" <= "$b")) > 大於(需要雙括號),如:(("$a" > "$b")) >= 大於等於(需要雙括號),如:(("$a" >= "$b")) 4)字符串比較: 通常是這樣做的: if [ X"$test" = X"test" ] = 等於,如:if [ "$a" = "$b" ] -d 目錄 -e 存在 -f 文件 -n 非空字符串 -z 空字符串 5)來點兒複雜的: have_program() { hash "$1" >/dev/null 2>&1 } # 下面if語句中調用的have_program若爲真,則判斷爲假,反之則進入if語句執行錯誤提示 dep_check() { if ! have_program "$1"; then exit_message "'${1}' command not found. Please install or add it to your PATH and try again." fi } # 判斷用戶的權限 if [ `id -u` -ne 0 ]; then echo "You must run this script as root." if [ -x /usr/bin/sudo ]; then echo "Try running 'sudo ${0}'." fi exit 1 fi >&2 # 判斷幾個命令是否可用 echo "Checking for required packages..." for pkg in rpm yum python curl; do dep_check "$pkg" done 3. for的用法 array1=("d.com" "e.com" "f.com") len=${#array1[@]} for ((i=0;i<$len;i++)) do echo ${array1[$i]} done for a in $(seq 1 100);do echo $a sleep 1s done 4. case的用法 case $1 in start|stop|reload) $1 ;; *) echo "Usage: $0 [start|stop|reload]" ;; esac 5. while的用法 while true do echo "abc" read -p "請輸入: " abc ddd="$abc" if [ ${#ddd} -ne 5 ]; then echo "請重新輸入!!!" else break fi done 和case結合的用法: while getopts "h" option; do case "$option" in h) usage ;; *) usage ;; esac done 和read結合的用法: 從文件中逐行讀入內容,拼接字符串 s='\n\n' while read line do s="${s}${line}\n" done </tmp/a.txt echo -e $s 和read ignore結合的用法: # echo 'a b c d e' |while read ignore args; do echo $args; done b c d e # echo 'a b c d e' |while read ignore ignore args; do echo $args; done c d e # cat /etc/init.d/network |grep static-routes --color -A 3 # Add non interface-specific static-routes. if [ -f /etc/sysconfig/static-routes ]; then grep "^any" /etc/sysconfig/static-routes | while read ignore args ; do /sbin/route add -$args done fi 其實,這裏的ignore也是一個變量: # echo 'a b c d e' |while read ignore args; do echo "$ignore $args"; done a b c d e # echo 'a b c d e' |while read ignore ignore args; do echo "$ignore $args"; done b c d e read後可以跟多個變量,依次接收傳遞過來的值。 6. 參數 [root@test t]# cat t.sh #!/bin/bash # # $0 是這個bash文件的名稱; # $1 是第1個參數; # $? 是上一指令的返回值; # $* 是該腳本調用的所有參數; # $@ 基本與上面的$*相同。區別是: # $* 返回的是一個字符串,字符串中用空格分隔開,而 $@ 則返回多個字符串; # $# 是所有位置參數的個數; # $$ 是返回上一個指令對應的pid # ab=($(ls)) echo '${ab[@] -> '${ab[@]} echo '${#ab[@]} -> '${#ab[@]} echo '$0 -> '$0 echo '$1 -> '$1 echo '$2 -> '$2 echo '$? -> '$? echo '$* -> '$* echo '$@ -> '$@ echo '$# -> '$# echo '$$ -> '$$ [root@test t]# sh t.sh zzz yyy xxx www -h ${ab[@] -> set_color.sh t.sh ${#ab[@]} -> 2 $0 -> t.sh $1 -> zzz $2 -> yyy $? -> 0 $* -> zzz yyy xxx www -h $@ -> zzz yyy xxx www -h $# -> 5 $$ -> 30383 7. 正則 正則表達式匹配"=~" [[ $XX =~ ^$XXX ]] The =~ Regular Expression matching operator within a double brackets test expression. $ [[ "# test2" =~ ^# ]] && echo yes || echo no yes 8. 截取字符串 假設有: f="/a/b/c/d/e.name.ext" 則: # basename $f e.name.ext # dirname $f /a/b/c/d 特殊用法:利用${}中的#,%,*來輸出指定的內容 1)去掉第一個/,以及左邊的字符串 # echo ${f#*/} a/b/c/d/e.name.ext 2)去掉最後1個/,以及左邊的字符串 # echo ${f##*/} e.name.ext 3)去掉最後一個/,以及右邊的字符串 # echo ${f%/*} /a/b/c/d 4)去掉第一個/,以及右邊的字符串 # echo ${f%%/*} (空) 上面,是根據“/”來做分割,也可以用“."來分隔,不妨一試。 # echo ${f#*.} name.ext # echo ${f##*.} ext # echo ${f%.*} /a/b/c/d/e.name # echo ${f%%.*} /a/b/c/d/e 9. 腳本放入後臺,輸出到日誌 sh test.sh >1.log 2>&1 & sh test.sh >/dev/null 2>&1 & 這裏需要理解幾個小東西的作用: /dev/null 理解成空設備,這是一個特殊的文件,這裏的作用是丟棄輸出的內容 2>&1 0 輸入 1 輸出 2 錯誤 這裏是將2重定向到1 & 將test.sh放入後臺執行,請思考,還有其他的什麼方式也可以將程序放入後臺? 10. 管道 通過“|” 把輸出導入到另一個程序的輸入中去處理,例如: echo 'abc, def' |cut -d ',' -f 1 11. 命令跟蹤調試 sh -x test.sh 12. 快捷鍵 Ctrl + a 切換到命令行開始 Ctrl + b - Move back a char Ctrl + c 終止命令 Ctrl + d 退出shell,logout Ctrl + e 切換到命令行末尾 Ctrl + l 清除屏幕內容 Ctrl + k 剪切清除光標之後的內容 ctrl + q 恢復刷屏 Ctrl + r 在歷史命令中查找 ctrl + s 可用來停留在當前 Ctrl + u 清除剪切光標之前的內容 Ctrl + y 粘貼剛纔所刪除的字符 Ctrl + z 轉入後臺運行 !! 重複執行最後一條命令 ↑(Ctrl+p) 顯示上一條命令 ↓(Ctrl+n) 顯示下一條命令 !$ 顯示系統最近的一條參數 13. 在shell中調用python的方法 # python <<'_EOF' import sys print(sys.version) _EOF 2.6.6 (r266:84292, Jan 22 2014, 09:42:36) [GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] shell傳遞中文到python出現異常時: export LANG="en_US.UTF-8"; /usr/local/bin/python3 xxx.py 14. 創建臨時目錄的方法 tempdir=`mktemp -d` cd "$tempdir" 15. 一個簡單的密碼生成方法 pw=`date +%N|cut -c1-8` man date查看: %N nanoseconds (000000000..999999999) man cut查看: ?-c, --characters=LIST select only these characters 16. 簡單ping一下C段的IP subnet=192.168.1; for i in {1..254}; do ping -c 1 -w 1 ${subnet}.${i} >/dev/null && echo "${subnet}.${i}: up" || echo "${subnet}.${i}: down"; done 17. 字符串反轉 # echo 'abcde' |rev edcba 18. crontab的用法 1)格式不清楚可以這樣: cat /etc/crontab 或者 man 5 crontab 2)注意:用戶權限,是否需要特殊的環境變量。 3)注意:特殊符合,例如:% 在 crontab 中是特殊的意義(換行) Percent-signs (%) in the command, unless escaped with backslash (\), will be changed into new-line characters, and all data after the first % will be sent to the command as standard input. 舉例: 【錯誤】 0 2 * * * echo 'test' >/tmp/test_$(date +%Y%m%d).log 2>&1 & 【正確】 0 2 * * * echo 'test' >/tmp/test_$(date +\%Y\%m\%d).log 2>&1 & 19. 在 shell 中使用 Here Document 的使用注意 常見寫法,可以使用變量: test=$(blkid /dev/vg0/lv01 |cut -d'"' -f2) cat <<_EOF >>/etc/fstab UUID=$test /data xfs defaults 0 0 _EOF 換一種,則無法使用變量: cat <<'_EOF' >>/etc/fstab UUID=$test /data xfs defaults 0 0 _EOF 20. 測試主機內存佔用狀況(模擬分配最少 1 GiB 內存) python -c "import time;d='a'*1024*10**6;time.sleep(3600)" & 21. 排序的疑問 [root@tvm01 ~]# cat a.test a b c d e a b c d e 1 2 3 4 5 1 1 2 2 3 3 [root@tvm01 ~]# cat a.test |uniq |sort 1 1 2 2 3 3 4 5 a a b b c c d d e e [root@tvm01 ~]# cat a.test |sort |uniq |sort 1 2 3 4 5 a b c d e 上述2者的效果不一樣,爲何? 原因:uniq命令隔行重複是無效的,針對這種情況,需要先用sort排序再uniq。 22、臨時啓用一個端口來測試 python -m SimpleHTTPServer 8081 這個簡單的http服務器,還可以當作ftp用 23、示例隨機字符的生成:得到一個MAC地址的3種方式 echo "AA:BB:`dd if=/dev/urandom count=1 2>/dev/null |md5sum |sed -e 's/^\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4/'`" echo "AA:BB:`for i in {1..4};do printf "%0.2X:" $[ $RANDOM % 0x100 ]; done |sed 's/:$/\n/'`" echo "AA:BB:`od /dev/urandom -w4 -tx1 -An |sed -e 's/ //' -e 's/ /:/g' |head -n 1`" 24、在shell中使用遞歸的一個小示例 需求:下載一個小說的文字內容。 ~]# cat test.sh #!/bin/bash # do_rewrite() { ff=$1 echo "[*] Convert -> ${ff}" wget -q http://www.zanghaihuawang.com/laojiumen/${ff}.html -O old/${ff}.html grep 'h2' old/${ff}.html >/dev/null if [ $? -eq 1 ]; then echo '[E] empty file.' exit 1 else cat <<'_EOF' >new/${ff}.html <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> </head> <body> _EOF sed -n '/<h2>/,/\[Enter\]/p' old/${ff}.html |sed 's/\/laojiumen\///' >>new/${ff}.html cat <<'_EOF' >>new/${ff}.html </body> </html> _EOF f_next=$(cat new/${ff}.html |grep 'pager_next' |grep -Eo '[0-9]+') if [ -z ${f_next} ]; then echo '[E] next file not found.' exit 2 else do_rewrite ${f_next} fi fi } do_gb2312_to_utf8() { #yum -y groupinstall "Development Tools" && wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz && tar zxvf libiconv-1.14.tar.gz && cd libiconv-1.14 && ./configure && make && make install for i in `ls new/`; do iconv -c -f gb2312 -t utf-8 test/$i >new_utf8/$i;done } mkdir -p old new do_rewrite $1 25、set的用途 1)設置參數 在腳本中: # cat t.sh set z1 y1 x1 w1 echo '$1 -> '$1 echo '$2 -> '$2 echo '$@ -> '$@ echo '$# -> '$# # sh t.sh z y x w $1 -> z1 $2 -> y1 $@ -> z1 y1 x1 w1 $# -> 4 在命令行: [root@ttt ~]# set z y x w [root@ttt ~]# echo $# 4 [root@ttt ~]# echo $@ z y x w 2)設置選項 set -e :命令執行結果不爲0,則退出 set -x :調試輸出 其他請參考man手冊 26、如何審計操作 提供一些思路: script PROMPT_COMMAND 用法,請搜索相關主題。 27、查看內存佔用: ps -u appuser -wo rss=,comm= --sort -rss | while read -r rss comm ; do echo $((rss/1024))"MB -" $comm; done |head -n 10 28、如何使用!$ [root@test ~]# ls /tmp/ cvm_init.log net_affinity.log sagent.pid setRps.log [root@test ~]# echo !$ echo /tmp/ /tmp/ 顯然,要調用上一條指令的最後一個參數,不妨試試 !$ 28、查看 ip=192.168.200.201 監聽的端口(8300-8599這個範圍的): ss -ant |awk '$4~/192.168.200.201:8[3-5]/ {print $0}' 29、防火牆常用操作 放行端口 iptables -A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 8080 -j ACCEPT iptables -A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 4000:4099 -j DROP 端口轉發 iptables -t nat -A PREROUTING -d 服務器外網IP/32 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 服務器內網IP iptables -t nat -A POSTROUTING -d 服務器內網IP/32 -p tcp -m tcp --dport 8080 -o eth0 -j MASQUERADE 30、查看和清理指定用戶下的進程 ps -U username ps -U username -L ps -U username |awk '{print $1}' |grep -Eo '[0-9]+' |xargs -i kill {} 31、$'string' 的用法 參考: http://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html https://stackoverflow.com/questions/18626209/bash-syntax-error-near-unexpected-token 是不是在 init.d 的腳本中常看到這樣一段: echo $"Usage: xxx" 這個 dollar sign $ 是啥意思呢? Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. 就是說,字符串前邊有個美元符號,意味着可以使用轉義符。 32、base64編碼解碼 echo -n "foo" |base64 base64 -d <<< "Zm9v" while read line; do cnt=$(echo $line |wc -c); [ $cnt -gt 1000 ] && continue; echo $line;echo -e '\n----->\n';echo -n $line |base64 -d; echo -e '\n\n'; done<1.txt 33、對比 here document 還有一種 here string 的寫法 << denotes a here document <<< denotes a here string $ cat <<< 'hi there' hi there read first second <<< "hello world" echo $second $first 34、進制轉換 16 進制 -> 10 進制 [root@dev8 run]# echo $((0x13b)) 315 10 進制 -> 16 進制 [root@dev8 run]# echo "0x$(echo "obase=16;315"|bc |tr 'A-Z' 'a-z')" 0x13b