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