shell脚本实用经验

1.查看某配置文件(过滤空行和注释行)

cat /etc/ssh/sshd_config | egrep -v "^#|^$"
cat /etc/ssh/sshd_config | egrep -v "^# | ^$"(引号内有空格是错误的)

2.$?能省就省(if condition;then …fi)

if who | grep -q "zhangsan" >/dev/null 2>&1;then
	echo "有zhangsan登录"
fi

while ! who | grep -q "zhangsan" >/dev/null 2>&1;do
   echo "zhangsan没有登录"
   sleep 3
done

3. 简单if能省就省

短路与和短路或(A&&B,A||B)
[[ -e "./ab.sh" ]] && echo "file exits"(A成立,B执行)
[[ -d ab ]] || mkdir ab (A不成立,B执行)
[ $? -eq 0 ] && echo "condition is true"
[ $a -eq 0 ] && echo "a=0" || echo "a=1" (简单if-else实现)

4.while逐行读取文件(避免while+管道,管道会fork子进程,造成子进程中的变量在循环外部无法取到)

while read line;do
    echo $line
done < /etc/passwd

5.while逐行读取内存中的信息,注意< <这种写法不能在nohup &中运行,java调用shell脚本时,这种写法也可能发生错误

while read line;do
    echo $line
done< <(ls -lrt /tmp/)

6.数组小技巧

list=( ( l s / t m p ) ) / / l i s t 变 成 数 组 因 为 我 们 知 道 l i s t 2 = ( " d o g " " p i g " " b e e " ) 是 数 组 赋 值 , 那 么 (ls /tmp)) //list变成数组 因为我们知道list2=("dog" "pig" "bee")是数组赋值,那么 (ls/tmp))//listlist2=("dog""pig""bee")(ls /tmp)其实是先做了命令行展开,
展开内容形如"dog" “pig” “bee” ,之后一起赋值给list
尝试list=(/var/log/*.log)

知道循环10次

for i in {0..9};do
	
done

使用下列方法遍历数组元素最好,其中$i表示数组的索引,避免遍历稀疏数组出现问题

array=([3]="he" [8]="gh")
for i in ${!array[*]};do
        echo "$i  ---->  ${array[$i]}"
done

数组的长度的使用

${#array[*]}
向数组末尾添加元素x:array[${#array[*]}]=x;前提是数组不是稀疏数组
向数组末尾添加数组,即数组衔接: array_new=(${array1[*]}  ${array2[*]})
一次输出数组所有元素:${array[*]}
删除数组中的某个元素:unset array[Index]

关联数组(也叫哈希,也叫map,是一组组键值对)

declare -A array(必须定义)
array=([index_name1]="value1" [index_name2]="value2")
例:
declare -A project
project=([bms]="java" [cms]="java" [rdms-proxy]="c++")
for index_name in ${!project[*]};do
        echo "$index_name" "${project[$index_name]}"
done

输出
bms java
rdms-proxy c++
cms java

例2
查看20736端口被哪一些主机建立连接,连接数目是多少,并排序

#map[ip]=ip_cnt,定义哈希,下标为ip,值为ip的数量
declare -A map 
check_port=20736

for ip in `netstat -tuna | grep $check_port | grep -v LISTEN | awk '{print $5}' | awk -F: '{print $1}' `;do
        if [[ -z map[$ip] ]];then
                map[$ip]=1
        else
                ((map[$ip]++))
        fi
done

**#按照第二列(连接数目)排序**
for index_name in ${!map[*]};do
        echo "$index_name" "${map[$index_name]}" 
done | sort -n -t ' ' -k 2

7.字符串切片:

字符串的长度 :${#str}
字符串切片:${var:offset:number} ; 去字符串最右侧的n个字符 ${var: -n}
基于模式取子串:
${var#*word}	word是指定分隔符,从左往右,在var中第一次匹配到word,删除var中从开头到分隔符之间的所有字符
${var##*word}	word是指定分隔符,从左往右,在var中最后一次匹配到word,删除var中从开头到分隔符之间的所有字符
${var%word*}	word是指定分隔符,从右往左,在var中第一次匹配到word,删除分隔符到字符串尾部的所有字符
${var%%word*}	word是指定分隔符,从右往左,在var中匹配到最后一次word,删除分隔符到字符串尾部的所有字符
mypath="/etc/init.d/functions"
${mypath#*/} etc/init.d/functions
${mypath##*/} functions

str=$(basename DH_RTRCS_Chn_QL_IS_V2.004.0000000.6.R.20200925.tar.gz)
${str%.tar.gz} DH_RTRCS_Chn_QL_IS_V2.004.0000000.6.R.20200925

url="http://www.magedu.com:80"
${url##*:}  80
${url%%:*}  http



8.shell 调试

bash -x test.sh 使用-x来作调试,可以看过程
bash -n test.sh 使用-n来进行语法检测

9.可以使用$?捕捉函数返回值

function return_test(){
        echo "进入函数体"
        return 77
}

return_test
echo $?

$?输出77

10.trap --陷阱触发(只要系统产生特定信号,trap就会触发指令)

trap 'commands' signal-list
trap "commands" signal-list
当然commands可以是函数调用
#/bin/bash
#使用单引号表示bash在读取到trap这行时先不会将$online_host代替掉
trap 'echo online_host is $online_host. down_host is $down_host.;exit 1' INT
online_host=0
down_host=0
for i in {1..50};do
        ping -w 1 -c 1 $1.$i &>/dev/null
        if [ $? -eq 0 ];then
                let online_host+=1
                echo "$1.$i is online"
        else
                let down_host+=1
                echo "$1.$i is down"
        fi
done

echo "online_host is $online_host. down_host is $down_host."
工作机制:当用户键入ctrl+c后, bash脚本和其子进程(ping)都看见sigint信号,(他们是前台进程组成员)。
ping接收到SIGINT时终止,bash接收到SIGINT时执行trap 'commands' signal-list,执行到exit1时退出bash

trap命令的一种常见用途是在脚本程序被中断时完成清理工作
#!/bin/bash
trap 'rm -rf  ${list[*]};exit 1' INT
i=0
while [ $i -lt 254 ];do
        ping -w 1 -c 1 10.35.78.$i &>/dev/null
        if [ $? -eq 0 ];then
                temp_file=$(mktemp /tmp/onlineXXXX)
                echo "10.35.78.$i" >$temp_file
                list[${#list[*]}]=$temp_file
        fi
        let i+=1
done
rm -rf  ${list[*]}

11.获取当前执行的shell脚本所在目录

CURRENT_DIR="$(cd "$(dirname "$0")"; pwd)"可以使用在该脚本同目录或者相对目录下的配置文件的路径中s

12 <<高级bash编程指南>>

http://www.reddragonfly.org/abscn/index.html

13 shell并发问题

13.下面的脚本输出值为1,因为&会将fuc中的内容放到子shell中进行,子shell中会另外定义一个变量a,但是不会影响主shell中的a(易错)

#!/bin/bash
a=1
function fuc () {
        a=2
}

fuc &
echo $a  //a=1

下面的脚本输出值为2,因为shell中的变量默认是全局变量,因此三个a变量其实是同一个a
#!/bin/bash
a=1
function fuc () {
        a=2
}

fuc 
echo $a //a=2
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值