linux bash shell 三言兩語

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章