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))//list变成数组因为我们知道list2=("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