脚本
- 脚本开头加 #!/bin/bash 指定运行的解析器,不是注释
- chmod u+x filename 加执行权限,如果不加权限可以 bash filename执行脚本
- 退出脚本 exit NUM 代表返回值 可以$?获取
特殊符号
~ 家目录 cd ~
! 执行历史命令 history 查看历史命令 !5 !! 执行上一条命令
$ 变量取内容符 $? 非0表示有问题 0表示没有问题
& 后台执行
* 匹配所有
? 匹配除回车以外的一个字符
; 命令之间用;分隔
| 管道
\ 转义字符
`` 命令中执行命令 echo "today is `date +%F`"
'' 字符串 但不解释变量 '$a' # $a 'Hello World !'
"" 解释变量 "$a" # 1 "Hello World \!" 如果包含特殊字符 需要加转义符\
特殊变量
IFS 内部字段分隔符 默认空白字符(换行符,制表符,空格)
$*:代表所有参数 间隔为IFS内定参数第一个字元 所有参数视为单个实体 "$1c$2c$3"
$0: 脚本的文件名
$@:与*类似,不参考IFS 以列表方式打印所有参数 "$1" "$2" "$3"
$#:参数数量 # length=${#var} 获取变量的长度
# echo $# | tr ' ' '\n' > file # 将空格转换为回车写入文件
$:执行上一条命令返回值
$-:执行的foreground pipeline的选项参数
$$: 本身的processid
# /tmp/cpu_usage.$$ $$为当前脚本的进程id 如果是1345,文件名就是cpu_usage.1345
$!:保存上一个命令的PID
$N:shell的第几个外传参数
shift 参数左移¥
for i in `seq 1 $#`
do
echo $i is $1
shift
done # 1 is a 2 is b 3 is c
# ./img_download.sh url -d images
while [ $# -gt 0 ]
do
case $1 in
-d) shift; directory=$1; shift ;;
*) url=$1; shift ;;
esac
done
重定向
> 重定向输入 覆盖原数据
>> 重定向追加输入,在原数据末尾添加
< 重定向输出 wc -l < /etc/passwd
<< 重定向追加输出 fdisk /dev/sdb << EOF ... EOF
# 向文件输入内容
cat < < EOF > test.sh # end of file
123
1231231
EOF
# 通过STDIN提供多行输入 出现在EOF之间的文本都会作为标准输入传给mysql
mysql -u $user -P$pass STUDENTS <<EOF 2>/dev/null
CREATE TABLE students(
id int,
name varchar(100),
);
EOF
# 写成多行用EOF
depts="`mysql ... students<<EOF
set @I:=0;
...;
`"
运算
let result=no1+no2
result=$[ no1 + no2 ]
result=$((no1+5))
result=`expr 3 + 4`
# expr 整数运算 要加空格
expr 1 + 1
expr 5 - 2
expr 5 \* 2 需要转义
expr 5 / 2 # 2 整数
# bc计算器可以保留小数
echo "scale=2;100/3" | bc # 33.33
hours=$(echo "$minutes / 60.0" | bc)
# (()) 双小圆括号
echo $((100**3))
# 将命令的输出赋给变量, 两种方式
cmd=$(COMMANDS)
cmd=`COMMANDS`
utime=$(ssh $(USER)@$(IP) uptime | awk '{ print $3 }') # 将结果保存在变量中
echo $utime
cur_date=$(date +%D)
# 赋值
NEEDED_INPUT_FILES="${NEEDED_INPUT_FILES} symaccess_list_view_detail symaccess_list_logins"
# 计算
lun_capacity=$(echo "${lun_capacity_array[$____index]}" | awk '{print int($0)/2/1024/1024}')
执行命令
(命令1;命令2;命令3) # 开启一个子shell环境来执行括号里的内容
{ 命令1;命令2 } # 将中括号的命令放在现成的shell执行
{
if [ "${LOCAL_SCRIPT_PARAM_VMAX_SID}" = "all" ]
then
... |
grep -v "^#" |
awk '{ print $1 }'
...
} | \
while read VMAX_SID VMAX_NAME
do
(( ii+=1 ))
A_VMAX_NAME[$ii]="${VMAX_NAME}" # 将VMAX名字,SID存入列表中
A_VMAX_SID[$ii]="${VMAX_SID}
done
输入输出
eval
变量的嵌套替换
var1="hello"
i=1
what=var${i}
temp=what
echo $temp # what
eval temp=$(echo \$$what) # $what=var1->echo $var1="hello" eval会将表达式中以$开头的所有变量进行整体替换
versions="(2 4)" # 字符串 eval versions="(2 4)" 数组 eval会把赋值语句中双引号之间的变量直接付给=前变量
eval $(printf "a=\"1234\" b=\"4556\"")
echo $a # 1234 会把标准输出中的内容进行赋值
eval echo \$$# 获取脚本中的最后一个参数
模拟指针
x=100
ptrx=x
eval echo \$$prtx # 100
eval $ptrx=50
exho $x # 50
# 环境变量添加
prepend() {[ -d "$2" ] && eval $1=\"$2\$\{$1:+''\$$1\} && export $1 ; } # ${parameter:+expression} 当parameter有值,则使用expression的值
echo
echo [-ne][字符串]
-n 不要自动换行
-e 搭配以下使用
\a 发出警告声
\b 删除前一个字符
\t 插入tab
\n 换行且光标移到行首
\f 换行光标在原位置
\c 不加换行符
echo -e "\33[字背景颜色;文字颜色m字符串\33[0m"
echo -e "\033[41;33m红底黄字\33[0m"
${command} # 直接运行command命令
文本切片 ${ \ \ }
echo ${var/line/REPLACED} # 将字符串中的Line替换为replaced
pusg=${pusg/\%/} # pusg中去掉%
echo ${string:4} # 打印字符串第5个字符及以后的字符
echo ${string:4:8} # 从第5个开始,打印8个字符
${string:(-1)} # 最后一个字符
${string:(-2):2} # 打印最后两个字符
# #
${变量#关键词} 将从头到尾满足关键词的最短匹配删除
${变量##关键词} 将从头到尾满足关键词的最长匹配删除
a="/home/stmrep/STMREP/collect/20200330-2031_VMAX8_linuxa"
echo ${a#*_} # VMAX8_linuxa
# %
${变量%关键词} 将从尾到头满足关键词的最短匹配删除
${变量%%关键词} 将从尾到头满足关键词的最长匹配删除
a="123.456"
echo ${a%\.*} 123 echo ${fc_name%\.*} 截取最后一个.之前的部分
# /
${变量/old/new} 将满足关键词的第一个old变为new
${变量//old/new} 将满足关键词的所有old变为new
printf 格式化字符串
printf "%-5s %-10s %-4s\n" No Name Mark # No Name Mark -表示左对齐,不指名则右对齐 .2保留两位小数 要加换行符\n
printf "%-5s %-10s %-4.2s\n" 1 wang 30.555 # 1 wang 30.55
printf "%-8s %-14s...\n" \
"date" "ip" "device" ... > $logfile # 将格式化标题写入日志文件
read
- 接受键盘的输入,回车表示结束
-p 打印信息
read -p "Enter: " var
-t 指定超时时间
-s 输入的不回显
-n 只读取前n个输入的字符
read -n 2 var 从输入中读取2个字符给var变量
-d 特定的定界符作为输入行结束
read -d ":" var # 当输入hello: var=hello
变量
- 内存在系统启动的时候按照1B为单位划分为若干块,进行统一16进制编号,对内存使用情况做记录,保存在内存跟踪表。
字节(1B) 字(2B) 块(512B) 千字节(1024B) 兆字节(1024KB) 吉字节(1024MB)
1GB = 1024 (MB) * 1024(KB) * 1024(B) * 8(bit)
内存占用:字符占一个字节(1B),字符串时字符串的长度加1字节长度(\0特殊字符,代表字符串结束)
SER = "ABC" 逻辑地址 对应 物理地址0X5...0X8
在建立变量时计算机将逻辑地址(变量名)和物理地址做对应
读数据时计算机根据物理地址找到逻辑地址,从对应的内存地址上读出数据返回
- 读取变量:echo $变量名
- 取消变量:unset name 全局变量:export name="wang"
- 本地变量:用户私有变量,只有本用户才能用,保存在bash_profile,.bashrc
- 全局变量:所有用户都可以使用,保存在/etc/profile,/etc/bahrc
- 变量是否用引号括起来
"双引号" 希望将文本视为字符串而不是正则表达式 禁止分词和全局搜索的上下文
'单引号' 字符串中禁止插值和反斜杠的特殊处理
无引号 希望分词和全局
words="hello world" for word in $words hello world(打印两次) , in '$words' $words, in "$words" hello world(打印一次)
pattern='file*.txt' ls $pattern (正确搜索) ls '$pattern' 搜索 $pattern ls "$pattern" 搜索file*.txt
echo "we have $count ${fruit}(s)" # 如果和其他字符串连接,需要加上{}
数组
基本数组
- 定义:数组名=(元素1,元素1.。。。)
array=(tom wang allen)
(`cat /etc/passwd`) # 将读出的每一行作为一个元素
(tom "bash shell")
# 不需要预先定义
array[0]='tom'
# 查看数组
declare -a
# 指定分隔符
oldIFS=$IFS
IFS=,
values=($line) # 以逗号为分隔符将line元素存入数组 1,wang p,98,cs
values[1]="\"`echo ${values[1]} | tr ' ' '#' `\""
SNAP_CG_NAME_ARRAY=(${NAME_ARRAY[@]}) # 数组变量的传递
src_lun_id_arr=($(echo $src_lun_id_str | tr ',' ' ')) # 字符串变数组
- 读取:${数组名[索引]}
echo ${array[0]} 单个元素
echo ${array[@]} 访问所有元素 <=> echo ${array[*]}
echo ${#array[@]} 统计元素个数
echo $[!array[@]} 打出所有元素索引
echo ${array[@]:1} 从下标1开始打印元素
echo ${array[@]:1:2} 从下标1开始访问两个元素
SNAP_CG_NAME_ARRAY=(${NAME_ARRAY[@]}) 数组变量的传递 注意:这种方式会丢失索引 从0开始
关联数组
- 定义:declare -A ass_array1
ass_array([index1]=val1 [index2]=val2)
ass_array[index1]=val1
逻辑比较
[ condition ] && action; # condition为真, 执行action
[ condition ] || action; # consition为假, 执行action
[[ $FAIL_CNT_19 -eq 0 ]] || return 10 第一个是真就不会再往右执行
[[ `grep -c 'Symmetrix ID' $NEEDED_F` -ne 1 ||
`grep -c 'Fibre' $NEEDED_F` -lt 1 ]] && (( VMAX8_ERROR+=1 ))
# check params
#
[[ $# -eq 4 ]] || return 1 左边不为真就会直接返回
流程控制
子shell
# 运行在子shell中
(
for ...
) >> $logfile
() | sort -nrk 4 | awk '{ printf("%-4s %s\n", NR, $0) }'
if
- 数学比较
-eq 等于
-gt 大于
-lt 小于
-ge 大于或等于
-le 小于或等于
-ne 不等于
- 字符串比较
== 等于 [[ $str1 == $str2 ]] # 字符串比较用双中括号
!= 不等于
-n 检查字符串长度是否大于0
-z 检查字符串长度是否为0 检查空字符串
- 文件比较
-d 文件存在且为目录
-e 检查文件存在
-f 文件存在且为文件
-r 检查文件存在且可读
-s 检查文件存在且不为空
-w 文件存在且可写
-x 文件存在且可执行
-O 文件存在且被当前用户拥有
-G 文件存在且默认组为当前用户组
file1 -nt file2 1是否比2新
file1 -ot file2 1是否比2旧
- 其他
&& 与 || ! = 赋值
[ $? -eq 0 ] && echo success || echo fail
-a AND &&
-o OR ||
! NOT !
- 语法
if [ condition 1 ]; then
commands
elif [condition 2 ]; then
commands
else
commands
fi
高级用法
for ((;;))
do
echo "hehe"
done
if [[ "$var" == r* ]]
echo "$var"
fi
双方括号可以在里面使用通配符
if [[ $param_value == ""|| $param_value =~ "description" ]] # 包含
then
fi
if [[ "${host_id[$index_host]}" =~ "(" ]] # 包含
for
- 语法
1
for var in value1 value2
do
commands
done
2 C形式
for ((i=1;i<10;i++))
do
echo $i
done
continue: 跳过某次循环
break:结束循环
break N:跳出某个循环 从内到外依次为1,2,。。。,N
break 2: 跳出外层循环
oldIFS=$IFS
IFS=":"
count=0
for item in $line
do
[ $count -eq 0 ] && user=$item # [] 里直接可以判断
[ $count -eq 6 ] && shell=$item
let count++
done
IFS=$OldIFS
echo $user's shell is $shell
# 遍历序列
echo {1..50} {a..z}
# 建立txt
for name in {1..100}.txt
do
touch $name
done
while
- 语法
while [ condition ] # 条件为真 继续循环
do
commands
done
IFS=$":"
while read f1 f2 f3 f4 f5 f6 f7
do
echo "$f1 $f2 $f3"
done < /etc/passwd
while read filename;
do
echo downloading $filename
done < /tmp/$$.list
util
until [ condition ] # 条件为假,继续循环
do
commands
done
case
read -p "NUMS: " N
case $N in
1) echo haha ;;
2) echo hehe ;;
3) echo heihei ;;
*) echo bye ;;
esac
# sqlite数据库
case $1 in
init) cmd="CREATE TABLE address (name string, phone string, email string);" ;;
query) cmd="SELECT name, phone, email FROM address WHERE $2 LIKE '$3';" ;;
insert) cmd="INSERT INTO address (name, phone, email) VALUES('$2', '$3', '$4');" ;;
esac
echo $cmd | sqlite3 $HOME/addr.db | sed 's/|/\n/g' # sqlite 执行命令并初始化输出
while [ $# -ne 0 ]
do
_OPT="$1" ; shift
f_stm_scripts_log_debug_message "$STM_SCRIPTS_RUN_CALLER_BASE: checking option $_OPT (= $1) "
case $_OPT in
"-d") LOCAL_SCRIPT_PARAM_DEBUG="on"
export STM_GLOBAL_DEBUG="on"
;;
"-e") if [ "${1}tIp" != "tIp" ]
then
LOCAL_SCRIPT_PARAM_ENV="${1}" ; shift
fi
;;
*) f_local_print_usage
f_stm_scripts_log_local_message "F" "invalid script call '$STM_SCRIPTS_RUN_CMD' "
f_stm_scripts_exit_script 1
;;
esac
done
函数
- 语法
1.
函数名() {
代码块
return N
}
2.
function 函数名() {
代码块
return N
}
repeat(){ while :; do $@ && return; sleep 30; done } # 当脚本传入的参数可执行就返回 否则死循环
# 文本文件数据库
Joe User~123 Example Street
function addr {
grep $1 $HOME/etc/addr.txt | sed 's/~/\n/g'
}
addr Joe
# Joe User
# 123 Example Street
命令
ln
硬链接 只删除一个链接不会导致文件的数据块和目录的连接被释放,inode与源文件相同
ln f1 f2
软连接 类似于windows的快捷方式,inode与源文件不同,只存有链接文件的位置信息
ln -s f1 f3
删除源文件,对硬链接无影响,会导致软连接无法访问,同时删除源文件,硬链接,文件才会被真正删除
cp
cp -r /home/stmrep/STMREP/collect/. /stmrep/incoming 文件夹下文件拷贝到另一个目录
kill
sudo kill -9 \`pidof app_data\`
dirname basename
dirname /usr/bin/sort # /usr/bin
dirname stdin.h # . 无/则获取当前目录
cd $(dirname "$0") # 跳转到脚本所在的路径
basename /usr/include/stdio.h .h # stdio 去掉文件名或后缀
basename /usr/include/stdio.h # stdio.h
/dev/null 2 > &1
cmd >a 2>a: stdout和stderr都会送往文件a, 啊会被打开两遍,由此会相互覆盖
cmd >a 2>&1 stdout送往a,stderr继承了FD1的管道后再送往a,这样a只会被打开一遍,不会相互覆盖
./test.sh > test2.log 2>&1
# line1 : command not found stderr
# date stdout
cmd > alloutput.txt 2 >&1
cmd &> output.txt # stdout和stderr都重定向到同一文件中
curl
# post请求是把参数放在HTTP消息主体发送,get请求是利用URL来发送参数
curl url -d "name=Clif&url=www.noucorp.com&http=..."
curl -H "Content-Type:application/json" -X POST -d '
{"username": "admin",
"password":"Admin@storage1",
"scope":"0",
"loginMode":"4"}'
-k -s -c $cookiefile https://${storage_ip}:8088/deviceManager/rest/xxxxx/login
curl -s -H "iBaseToken:7AFECB16F6B38FC87CB8DA00C063D90A39FEDC324C0CAF6CAD8150879A1B33F5" -b "ismsession=20779D3499EBF06DB67CA271969AE2C693087CADB8AF38BC5C30CA4B64B524EA" -k -X GET https://8.46.8.110:8088/deviceManager/rest/2102351NYH10J9000013/diskpool/count
--user-agent 设置代理 # curl URL --user-agent "Mozilla/5.0"
-b 发送cookie -b 'foo=bar' -b 'foo2=baz' -b cookies.txt
--cookie curl http:\\www.example.com --cookie "user=username;pass=hack"
-c 将服务器设置的cookie写入文件
-C 指定文件偏移处下载 -C offset(以字节为单位整数) -C -URL 断点续传
-d 发送post请求的数据体 -d 'login=emma&password=123' -d '@data.txt' 自动加上表头 Content-type:application/x-www-form-urlencoded
--data-urlencode 类似-d 区别会自动对发送数据进行url编码 --data-urlencode 'comment=hello world'
-F 上传二进制文件 -F 'file=@photo.png' 会加上请求头Content-Type:multipart/form-data 将png文件作为file字段上传 -F 'file=@photo.png;type=image/png' 指定MIME类型 -F 'file=@photo.png;filename=me.png' 指定服务器接收到的文件名是me.png
-H 添加HTTP请求头 -H 'Accept-Language:en-US' -H 'Secret-Message:xyz'
-I --head 只打印头部信息 不用下载整个文件
-d '{"login":"emma"}' -H 'Content-Type:application/json'
-k 跳过ssl检测 不会检查SSL证书是否正确
--limit-rate 限制请求和响应的带宽,模拟慢网速 --limit-rate 200k 带宽限制在200k
--max-filesize 可下载最大文件的大小 下载成功返回0 失败返回非0
-o 将响应保存为文件 -o example.html
-O 将响应保存为以URL最后部分命名的文件 -O http://.../bar.html 文件名:bar.html
-s --slient不再输出错误信息 不发生错误 就正常显示 -s -o /dev/null 不显示任何结果
-S 只输错误结果
-u 设置服务器认证的用户名密码 -u 'bob:12345' 将其转换为HTTP标头 Authorization: Basic Ym9i0jEyMzQ1
-v --trace 输出通信整个过程
-x 指定HTTP请求的代理 不指定默认HTTP
-X 指定请求方法 -X POST
cat
cat -s 压缩相邻的空白行
cat -T 将制表符标记成^T
cat -n 加上行号
head tail
head file # 打印10行
head -n 4 # 打印前4行
head -n -5 # 打印除了最后5行以外的所有行
tail -n 5 # 打印最后5行
tail -n 1 # 打印最后一个
tail -n +6 # 除了前5行之外的所有行
tail -f file # 从尾部不断监视文件的内容 -s 睡眠间隔
PID=$(pidof gedit)
tail -f file.txt --pid $PID # 监控文件,当关闭编辑器 tail结束
find
find /home -name '*.txt' -print
# . 表示当前目录
find . \( -name '*.txt' -o -name '*.pdf' \) -print # -o 或 -and 与
find . -regex '.*\.\(py\|sh\)$' 匹配.py或.sh文件 -iregex 忽略大小写
find . ! "*.txt" -print 排除匹配到的文件
find . -type d -print 只列出目录
find . -type l -print # 列出当前目录下的符号链接
find . -type f -name "*.php" ! -perm 644 -print 找到权限不是644的php文件
find . -type f -name "*.swp" -delete 删除匹配的文件
find path -type f -name "*.mp3" -exec mv {} target_dir \ # 将mp3文件移入给定的目录
find path -type f -exec rename 's/ /_g' {} \ # 将找到文件的所有空格替换为_
find . -exec sh -c 'echo -n {} | tr -d "[:alnum:]_.\-" | tr "/" " "; basename {}'
# mail
# statistics 将文件名的字母数字下划线等去掉,再把斜线转换为空格,再获取最后一级目录或文件显示目录树
for d in `find . -type d`
do
echo `find $d -type f | wc -l` files in $d # 103 files in . 统计目录下文件数
done # 17 files in ./cpus ...
# 找到文件进行替换
find . -name *.cpp -print0 | xargs -I {} -0 sed -i 's/Copyright/Copyleft/g' {}
find . -name *.cpp -exec sed ...'' \{\} \
find . -name *.gcda | xargs -n 1 -i cp -rf --parents(保留文件属性) {} /home/BDM_HLT/build/build/dorado_aa_code/AA-BDM/
xargs
xargs命令重新格式化stdin接收到的参数,再将其作为参数传递给指定命令
cat example.txt | xargs # 将多行输入转换为单行输出
cat example.txt | xargs -n 3 # 设置每行3个 参数
cat example.txt | xargs -n 1 ./cecho.sh # ./cecho.sh arg1 arg2 arg3 xargs添加的命令放在指定命令的尾部
cat example.txt | xargs -I {} ./cecho.sh -p {} -l # 命令替换站位
# ./cecho.sh -p arg1 -l
# ./cecho.sh -p arg2 -l
find source_code_dir_path -type f -name "*.c" -print0 | xargs -0 wc -l # 统计指定目录下c程序文件的行数
# 最好添加0字符作为结束标志符 再用xargs用0分隔 因为xargs默认用空格分隔
# -I -i 将一行赋值给后面的替代符
find . -name '*.sh' | xargs -I ^ sh -c "echo -ne '\n ^: '; grep main ^" # 找出所有sh脚本下 含main的行并打印 sh -c 是调用子shell来执行命令行脚本
./test_token.sh:
./rest_test.sh:
./test.sh: main 1121212122
find . -type f -exec du -k {} \; | sort -nrk 1 | head # 找出指定目录中最大的十个文件
tr
可以对标准输入的内容进行替换,删除,压缩
tr [options] set1 set2 集合1映射到集合2 当1大于2,2会不断复制1最后一个字符;当2大于1,2多余部分被忽略
echo "HELLO" | tr 'A-Z' 'a-z' # hello
集合定义 'ABD-}' 'aA.,' 'a-ce-x' 'a-c0-9' '\t' '\n'
echo 12345 | tr '0-9' '987654321' # 87654
tr '\t' '' < file.txt # 制表符替换
# 删除
echo 'Hello 123 World' | tr -d '0-9' # Hello World
# 补集
echo hello 123 | tr -d -c '0-9' # 删除不在0-9中的字符 123
echo hello 1 char 2 | tr -c '0-9' '' # 将不在0-9的字符替换为空格 1 2
# 压缩
echo 'GUN is not Unix' | tr -s ' ' # 去掉多余空格 GUN is not Unix
cat sum.txt | echo $[ $(tr '\n' \+) 0 ] # 将换行符换为+,并在最后填0,将1+2+3+4+5 赋给$ [] 进行运算 15
# first 1
# second 2
# third 3
cat test_tr.sh | tr -d [a-z] | echo "$[ $(tr " " "+") ]" # 6 牛皮
# 字符类
tr [:class:] [:class:]
users | tr ' ' '\n' | sort
sort
sort,uniq 从特定文件或stdin读取输入,并写出stdout
sort file1.txt -o(>) sorted.txt
sort -n # 按数字排序
sort -r # 逆序
sort -M # 月份
sort -m sorted1 sorted2 # 合并两个排好序的文件
sort 1.txt 2.txt | uniq # 找出已排序文件中不重复的行
if sort -c fileToCheck ; then echo sorted ; else echo unsorted ; fi
sort -nrk 1 data.txt # 按照第一列 逆序排序 -nr 按照数字逆序排列 k 指定排序依照字符 单个字符表示列号
sort -bk 2.3,2.4 data.txt # 按照第二列的起始第三个字符终止第四个字符排序
sort -nk 1,1 data.txt # 以第一个字符排序
sort -z data.txt | xargs -0 # 是sort输出与以\0为终止符的xargs匹配
sort -bd # 忽略空白按照字典顺序排序
# 与uniq结合
sort unsorted.txt | uniq # 显示不重复的行 <=> sort -u unsorted.txt 去重
ls -1 /stmrep/incoming/*_VMAX8_linuxa_* | awk -F"/" '{ print $NF }' | cut -d"_" -f4 | sort -u | egrep -vi 000297801855
sort unsorted.txt | uniq -c # 统计各行在文件中出现的次数
uniq -d # 找出重复的行
uniq -s 2 -w 2 # 指定跳过前两个字符 使用接下来的两个字符
uniq -z file_names.txt | xargs -0 rm # -z生成0字节终止字符,将多个重复的文件名只传递给rm一次,防止出现rm重复文件名不存在的错误
... sort | uniq # 管道去重
dd
克隆给定的输入内容,将一模一样的副本输出
dd if=/dev/zero of=junk.data bs=1M count=1 # 创建内容全为0,1MB大小的文件junk.data
wc
wc -l file # 统计行数
cat file | wc -w # 统计单词数
wc -c # 统计字符数
wc -L # 最长那行的长度
LINE_CNT=`wc -l $NEEDED_F | awk '{ print $1 }'`
LINE_CNT=${LINE_CNT:-0} 文件长度
cut
提取指定位置或列之间的字符
cut -f 2,3 filename # 提取2,3列
--complete 显示没有被-f指定的字段
cut -f2 -d"," # 以分好分割,取第二列
N- 从第N个到行尾
N-M 从N个到M个
-M 从第一个到第M个
-b 字节
-c 字符
-f 定义字段
cut -c2-5 打印第2到第5个字符
cut f.txt -c1-3,6-9 --output-delimiter "," # 指定输出以逗号分割
# abc,fghi
# abc,fghi
echo "(123)" | cut -d "()" # 123 去除括号
# 查看制定字段是否重复
grep "Bound Pool Name" $VMAX8_SYMDEV_V_INPUT_FILE | sort -u | wc -l
差并集
comm A B
apple
carrot
cookies
gold
silver
输出第3列 # 交集
输出第1列 # A有B没有
输出第2列 # B有A没有
comm A B -3 | tr -d '\t' # A B中互不相同的行 去掉制表符 删除第三列
comm A B -2 -3 # A的差集
sort B C | comm - A # BC排序后和A比较
grep
- 文本搜索工具,能使用正则表达式搜索文本并把匹配的行打印出来
- 命令格式:grep [option] pattern file
命令参数
-a 将二进制文档以文本方式处理
-A(n)除了显示匹配行,还要显示之后的n行 -A2
-b 显示该行第一个字符的编号 出现在行中的偏移
-B(n) 除了显示匹配行,还要显示之前的n行
-c 显示符合条件的匹配行数
if [ `echo "${INPUT_FILE_PATTERN}" | grep -c "<env>"` -eq 1 ]
then
INPUT_FILE_PATTERN=`echo "${INPUT_FILE_PATTERN}" | sed "s/<env>/${LOCAL_SCRIPT_PARAM_ENV}/"`
else
INPUT_FILE_PATTERN="${INPUT_FILE_PATTERN}*${LOCAL_SCRIPT_PARAM_ENV}*"
fi
if [ `grep -c '^Symmetrix ID:' $tmpPF` -eq 1 ]
egrep -c 'Device Symmetrix Name|Device Capacity' $NEEDED_F
VALUE_CNT=${VALUE_CNT:-0}
-C(n) 除了显示匹配行,还要显示该行之前之后n行
-e 指定多个匹配模式
-f 读取文件中的模式 一行代表一个模式
-i 不区分大小写
--include --exclude 使用通配符指定包含或排除某些文件
grep "main()" . -r --include *.{cpp} # --exclude "README"
-l 匹配模式所在的文件 -L 不在的文件
grep "test" file* -lZ | xargs -0 rm # 与xargs连用用-z使用0值作为文件名的终结符
-q 静默 不会输出内容 0表示匹配成功 非0表示匹配失败
-v 打印出不匹配的所有行
-n 显示出匹配项和行号
-x 全字匹配
-o 只显示匹配到的内容
-r(R) 递归查找文件夹
-E 支持正则表达式 <=> egrep
正则
^ $ .(非换行符的字符) []
*(0个多个先前字符) '*grep' 匹配一个或多个空格后紧跟grep的行
[^] 匹配不在这些范围内的字符 [^A-FH-Z]rep 匹配不包含^A-FH-Z开头,紧跟rep的字符
\(..\) 分组 标记匹配字符 # \(love\) 被标记为1
\< 匹配单词开始 '/<grep' 匹配包含以grep开头的单词
\> 匹配单词的结束 'grep\>' 匹配以grep结尾的单词的行
x\{m\} # 重复x m次
x\{m,\} # 重复x 至少m次
x\{m,n\} # 重复x m<= <=n次
() 将括号内容视为一个整体 ma(tri)?x 匹配max或matrix
| 匹配两边的任意一项 Oct(1st | 2nd)
\w 字符数字 <==> [A-Za-z0-9]
\W 非单词数字字符
\b 边界 单词锁定 # '\bgrep\b' 只匹配grep
cntrl: 控制非打印字符
graph: 图形提付
xdigit: 十六进制字符
[[:digit:]] [0-9] 外层中括号表示其中一个字节
[[:lower:]] [a-z]
[[:upper:]] [A-Z]
[[:alpha:]] [a-zA-Z]
[[:alnum:]] [0-9a-zA-Z]
[[:space:]] 空白字符
[[:punct:]] 标点符号
案例
( +[a-zA-Z]+[?,.]? +) # 匹配任意单词
grep test test* # 查找前缀是test的文件中包含test字符串的文件
grep -r update /etc/api 递归查找文件夹
grep -r f_local_check_env NMAX8/ 找文件夹下所有文件中的匹配项
grep "^[^48]" 匹配行首不以48开头的行
grep "K...D" 匹配KD中间是任意三个字符
20200327-1113_VMAX8_linuxa_000297801855_symcfg_show_pool.DG1_F_2
# ls -1 /stmrep/incoming/*_VMAX8_linuxa_* | grep "_symcfg_show_pool...*$"
grep '/bin/bash$' /etc/passwd | cut -d: -f1 | sort -n -r | head -1 显示结果中ID号最大的用户
netstat -tan | grep 'LISTEN[[:space:]]*$' 以LINSTEN结尾行
grep '\(\<[[:alpha:]]\+\>\).*\1r' wangTest 匹配一行中存在以某一单词加r的单词的行 He love his lover
echo -e "1 2 3 4\nhello\n5 6" | egrep -c "[0-9]" # 2 只统计匹配行数
改进 ... | egrep -o "[0-9]" | wc -l # 6
grep "test_function()" . -R -n <=> find . -type f | xargs grep "test_function()"
# 查询IP地址
ifconfig wlan0 | egrep -o "inetaddr:[^ ]*" | grep -o "[0-9.]*"
# 查找文件G_SHA256_CHECK_FILE_NAME中包含完整file单词这行,将这行开头的[0-9a-f]替换为L_MD5_RET
sed -ri "/\<$file\>/s/^[0-9a-f]+/$L_MD5_RET/" $TMP_TAR_DIR/$G_SHA256_CHECK_FILE_NAME
关联数组
- 关联数组允许用户自定义数组索引
- 定义:declare -A array
# 赋值
array[index]=pear
array=([index1]=tom [index2]=wang [index3]='bash')
awk
- awk是一种能处理数据,产生格式化报表的语言。
- 每一行是一条记录,记录与记录之间用换行符作为分隔符"\n",每一列是一个字段,字段与字段间用空格或tab制表符作为分隔符
- 工作方式:将每一行数据视为记录(record),每条记录以字段分隔符分为多个字段,再输出各字段的值。
- 语法 awk [options] [BEGIN]{program}[END] [file]
-F fs 指定一行中的字段分隔符 默认空格
-f file 指定读取程序的文件名
-v var=value 定义awk程序中的变量和默认值
# 还有种方法也可以传递参数值, 变量紧跟在代码块后
var1="variable1" var2="variable2"
echo | awk '{print v1,v2}' v1=$var1 v2=var2
注:'{}' 要将脚本命令放在大括号之内,大括号包在单引号之内
- 优先级:1.BEGIN:开始处理数据流之前,可选 2.program:处理数据流,必选 3. END:处理完数据流之后执行,可选
基本用法
- 字段相关内置变量 1文本中第一个字段 N 第N个数据字段 $NF最后一个数据字段
awk '{print $0}' test 打印整个文本
awk '{print $6}' 打印每一行的第6个字段
awk '{print $NF}' 打印每一行最后一个字段
awk -F ':' '{print $1,$3,$NF}' /etc/passwd 对每一行以:分隔字段,并打印第1,3,和最后一个字段
awk -f abc test # abc为写入awk program的文件 {print $1,$3} 根据文件内容处理流
awk -v name='wang' 'BEGIN{preint name}' 定义变量 输出该变量 BEGIN可以不用流 数据源
# 双引号里使用命令参数 并使用getline接受回显
awk 'BEGIN{"echo hahaha" | getline; print $0}'
- 提取某一行:提取记录 NR 指定行号
awk 'NR==3{print $0}' test 打印第三行 <==> awk 'NR==10' file.txt # 打印第十行
awk '$1=="3"{}print $0' 打印第一个字段是3的那一行的第一个字段
awk 'NR==M, NR==N' file # 打印从M行到N行的文本
- 提取某个字段
awk 'NR==3{print $6}' 第三行第6列
- 程序优先级:BEGIN最高优先级代码块,不需要提供数据源,不依赖PROGRAM;PROGRAM是对数据源进行处理,必选代码块;END在处理完数据源后进行操作,依赖PROGRAM,无法单独执行
awk 'BEGIN{print "hello world"}{print $0}END{print "bye world"}' test
awk 'BEGIN{print "hello world"}' begin不需要数据源
awk '{print "hello"}'
awk 'END{print "hello"}' 无数据源 无法执行
高级用法
cat collect_VMAX8.input | awk -F";" '$1 == "000297700138" { print }' | wc -l # 第一行发现了
getline
- 如果找到一条记录,返回1,到了结束(EOF)返回0,错误返回-1
awk 'BEGIN{"cat data.txt" | getline d; print d}' data2.txt
awk 'BEGIN{"cat data.txt" | getline; print $0}'
awk 'BEGIN{getline d < "data.txt"; print d}'
# 打印data.txt的第一行
awk '{getline < "data.txt"; print $0}' # awk首先读取第一行,getline把下一行给$0
awk 10 | awk '{getline;print}' # 打印偶数行
awk 'BEGIN{"date" | getline date; print date}' # 打印日期
awk 'BEGIN{ while( getline line < "grep.test" ){ print line } }' # 读取文件
# 在begin语句块读取文件头部信息,主语句块读取余下信息
seq 5 | awk 'BEGIN{getline; print "first line", $0}
{print $0}' # first line 0
# 2
# ...5
# 使用双引号可以读取命令输出
awk 'BEGIN{FS=":"}{"grep root /etc/passwd" | getline; print $1,$6}'
awk数组
- 定义数组:数组名[index] = value
- awk数组是一种关联数组 下标可以是数字或者字符串 支持多维数组,awk默认会吧数字下标转为字符串,本质上是是使用字符串作为下标的数组
- awk数组可以定义空字符串 huluwa[5]="",因此不能用huluwa[5] == ""来判断元素是否存在 ,在引用不存在的元素时也会自动创建 因此 huluwa[6] == ""也不能用来判断元素时会否存在 应当使用 if (6 in huluwa) {print "6号元素存在"}
if !(6 in huluwa){print "第6个元素不存在"}
遍历数组, 无序
awk 'BEGIN{array[0]=100;array[1]=200;print array[0],array[1]}' # 100 200
{for (item in array) print item,array[item]}
- 实例
{a="test";print a;a=a+1;print a;a++;print a} # test 1 2 当变量为字符串参与运算时,会被当做0进行运算
{print test["ip"];test["ip"]++;test["ip"]++;print test["ip"]} # 空 2
# 当引用了不存在的元素时,元素被赋值为空字符串,在进行自加时,就往上加1
# 统计ip
192.168.1.1
192.168.1.2
...
awk '{count[$1]++}END{for (i in count){print i,count[i]}}' test10
192.168.1.12 1
192.168.1.1 2
...
# 统计人名出现次数
Allen Philip
Wang...
awk '{for (i=1;i<=NF;i++){count[$i]++}}END{for (i in count){print i,count[i]}}'
Jack 1
James 1 ...
- 二维数组
awk '
BEGIN{
for(i=0;i<3;++i){
for(j=0;j<4;++j){
dict[i,j]=100
}
}
}
END{
for(key in dict) {
split(key, subkey, SUBSEP); # 分隔字符串
print subkey[1], subkey[2], dict[subkey[1],subkey[2]
}
}' $*
正则
# 打印位于开始模式到结束模式之间的文本
awk '/start_pattern/, /end_pattern/' file
echo -e "cat\nbat\nfun\nfin" | awk '/f.n/' # fun fin fan
... | awk '^The' # There Their
... | awk '/[CT]all/' # Call Tall
'/Colou?r/' # u变成可选字符 Colour Color
/bin/gawk '
/Pool Name/ {
poolname=$4;
}
/Enabled Devices/ {
flag="enabled";
}
/Disabled Devices/ {
flag="disabled";
}
$NF == "Enabled" && flag == "enabled" {
# Sym dev Enabled Devices
DEVICE=$1;
# Alloc MBs
DEVICE_USED=int($3)/1024;
gsub(" ", "", DEVICE);
if (pooltype == "Thin" && "'${SRP_NAME}'" != "")
{
print DEVICE";"DEVICE_USED";enabled;'${SRP_NAME}';;";
}
else
{
print DEVICE";"DEVICE_USED";enabled;"poolname";;";
}
}
$NF == "Disabled" && flag == "disabled" {
DEVICE=$1;
DEVICE_USED=int($3)/1024;
gsub(" ", "", DEVICE);
if (pooltype == "Thin" && "'${SRP_NAME}'" != "")
{
print DEVICE";"DEVICE_USED";disabled;'${SRP_NAME}';;";
}
else
{
print DEVICE";"DEVICE_USED";disabled;"poolname";;";
}
}' \
>> $VMAX8_DEVICE_OUTPUT_FILE_TMP_CAPACITY
cat $VMAX8_SYMCFG_SA_INPUT_FILE | \
/bin/gawk -F":" '
{
if ( $1 ~ "Director Identification" ) { FA=$2; }
if ( $1 ~ "Director Type" ) { PORTTYPE=$2; }
if ( $1 ~ "Director Port$" ) { PORTNAME=FA":"int($2); }
{
PORTSTATUS=$2;
sub("line", "", PORTSTATUS);
}
if ( $0 ~ "Access_Logix" ) { MASKING_ENABLED=$2; }
if ( $1 ~ "Show_ACLX_Device" )
{
print PORTNAME";"PORTWWN";"PORTTYPE";"PORTSTATUS";"MASKING_ENABLED";"
}
}' | \
sed "s/^/${LOCAL_SCRIPT_INPUT_TIME};${LOCAL_SCRIPT_COLLECTION_DATE_TIME};flat file;${SSUB_SID};${SSUB_MODEL};emc;/" | \ sed -e "s|; |;|g" >> $VMAX8_PORT_OUTPUT_FILE
运算
赋值运算
awk -v name='wang' 'BEGIN{print name}'
awk 'BEGIN{school="wang";print school}'
比较运算 > >= == <= !=
awk 'BEGIN{print "a" >= "b"}' # 0 非真
awk '$1>4{print $0}' 打印第一个字段大于4的行到的第0个字段
数学运算 + - * / % ** ++ --
awk 'BEGIN{print 100/3}' # 33.333
awk -v 'count=0' 'BEGIN{count++;print count}' # 1
逻辑运算
awk 'BEGIN{print 100>=2 && 100>=3}' # 1
匹配运算 ~ ~!
awk -F ':' '$1 ~ "^ro"{print $0}' /etc/passwd 打印所有第一个字段以ro开头的行
awk -F ':' '$1 !~ "^ro"{print $0}' 打印所有第一个字段不包含ro的所有行
环境变量
# FILEWIDTHS:以空格分隔的数字列表,用空格定义每个数据字段的精确宽度
awk 'BEGIN{FILEWIDTHS="5 2 8"NR==1{print $1,$2$3}}' /etc/passwd # 源行root:x:0:0:root:/root:/bin/bash => root: x: 0:0:root
# FS:指定数据源中的字段分隔符 类似-F
awk 'BEGIN{FS=":"}NR==1{print $1,$3,$NF}' /etc/passwd # root 0 /bin/bash
# OFS:指定输出到屏幕后字段的分隔符
awk 'BEGIN{FS=':';OFS="-"}NR==1{print $1,$3,$NF}' # root-0-/bin/bash
# RS:指定记录的分隔符 以什么方式分隔行
awk 'BEGIN{RS=""}{print $1,$13,$25,$37,$49}' test # 本来是有多行 以空行为分隔符分隔行时,所有字段就都在一行了 1 2 3 4 5
# ORS:输出到屏幕的分隔符 默认回车
awk 'BEGIN{RS="";ORS="*"}{print $1,$13,$25,$37,$49}' # 1 2 3 4 5*[root@wang] 提示符和输出符在一起了 因为默认回车符换成了*
流程控制
if 判断语句
awk '{if($1>5)print $0}' num 打印num中第一个元素大于5的行
awk '{if($1>5)print $1/2;else print $1*2}' num
for 循环语句
awk '{sum=0;for (i=1;i<4;i++){sum+=$i}print sum}' num2 将每行的前三个元素相加并打印
awk '{for(i=1; i<=NF; i++) {print $i}}'
controller_id_str=$(echo ${controller_id_array[@]} | awk '{for(i=1; i<=NF; i++) {print $i}}' | sort -u)
STM_SCRIPTS_RUN_CMD=`echo $STM_SCRIPTS_RUN_CMD | awk '{
flag="no";
str1="";
for(i=1; i<=NF; i++){
if (flag=="yes") {
str1=str1"**** "
flag="no"
continue
}
if ($i=="-e"){
flag="yes"
str1=str1$i" "
} else {
str1=str1$i" "
}
}
print str1
}'`
while 循环语句
awk '{sum=0;i=1;while(sum<150){sum+=$i;i++}print sum}' num2 当每行的和大于150时就终止这行的循环
do while 循环
awk '{sum=0;i=1;do{sum+=$i;i++}while(sum<150);print sum}' num2
# 包含
if ( $1 ~ "Director Identification" ) { FA=$2; }
ii=0
{
# cat collect_VMAX8.input | grep -v "^#" | awk '{print $1}'
if [ "${LOCAL_SCRIPT_PARAM_VMAX_SID}" = "all" ]
then
cat ${VMAX8_INPUT_FILE} | \
grep -v "^#" | \
awk '{ print $1 }'
else
cat ${VMAX8_INPUT_FILE} | \
awk '{ print $1 }' | \
awk -F";" '$1 == "'${LOCAL_SCRIPT_PARAM_VMAX_SID}'" { print }'
fi
} | \
awk -F";" '{ print $1, $2 }' | \
while read VMAX_SID VMAX_NAME
do
(( ii+=1 ))
A_VMAX_NAME[$ii]="${VMAX_NAME}" # 将VMAX名字,SID存入列表中
A_VMAX_SID[$ii]="${VMAX_SID}"
done
特殊变量
awk 'END{print NR}' test # 统计行数 5 NR在函数体中是当前的行数,在END中是最后一行的行数
awk 'END{print $0}' test 打印文本最后一行
awk 'END{print NF}' test 打印文本列数 看长度可用
basename 20200327-1113_VMAX8_linuxa_000297801855_symcfg_v_list | awk -F"_" '{ print $(NF-3) }'
# 000297801855
# 看倒数几个的值
`basename ${DORADO_FC_PORT_INPUT_FILE} | awk -F"_" '{ print $(NF-3) }'`
# 逆序
seq 9 | awk '{lifo[NR]=$0}END{
for(lno=NR;lno>-1;lno--){ # END里的NR表示最后一行
printlifo[lno]
}
}'
处理函数
length(string) 返回字符串长度
index(string,search_string)
split(string, array, delimiter) # 将delimiter作为分隔符分割string,结果存入array
substr(string, start-position, length) # 返回子串
匹配 DG1_F_F TEFEEI RAID-5(7+1) 21742396 4589136 17153264 79 0
awk 'substr($2,1,1) == "T" && substr($3,1,1) != "U" && ( NF == 8 || NF == 9 ) { print $1 }' ${OUT_PREF_19}_symcfg_list_pool
echo "TEFEEI" | awk '{TYPE=substr($1, 2, 1) ;print TYPE} # E
echo "TEFEEI" | awk '{TYPE=substr($1, 2, 2) ;print TYPE} # EF
sub(regex, replacement_str, string) # 将正则表达式regex匹配到的第一处内容替换为repalcement_str
sub("^ *", "", $i) 去掉空格
gsub(" ", "", SSUB_DEVICE_NAME)
awk '{gsub(/^\s+|\s+$/, "");print}' 去掉前后空格
sub("^ *| *$", "", param_array[2])
gsub(...) # hesub类似,不过会替换所有内容
awk '{gsub(/"|\[|\]|data:|,|{|}/,""); print $0}')
match(regex, string) # 检查字符串能否找到匹配,找到返回0,否则返回非0
tolower(param_array[1]) # 大写变小写
实例
cat contacts
Riley Mullen
123 Main Street
Chicago,IL 60602
(312)555-1234
Riley Mullen
123 Main Street
Chicago,IL 60602
(312)555-1234
Riley Mullen
123 Main Street
Chicago,IL 60602
(312)555-1234
awk 'BEGIN{RS="";FS="\n"}{print $1,$4}' contacts # 先用空白分隔行 再以回车分隔列 取1,4列
Riley Mullen (312)555-1234
Riley Mullen (312)555-1234
Riley Mullen (312)555-1234
# cat ip
192.168.1
192.168.2
192.168.3
172.16.3
192.16.1
192.16.2
192.16.3
10.0.4
awk 'BEGIN{RS="",OFS="\n"}{print $1 "-" $3,$4,$7 "-" $4,$8}' ip
192.168.1-192.168.3
172.16.3
192.16.3-172.16.3
10.0.4
awk '{sum+=$1}END{print sum}' num 求所有第一个字段的和
# 统计连接状态的数量
netstat -antpl | awk '{array[$6]+=1}END{for(i in array) print array[i],i}'
4 LISTEN
3 SYN_RECV
3 ESTABLISHED
1 established)
1 FIN_WAIT1
1 Foreign
42 TIME_WAIT
统计词频
- 写一个 bash 脚本以统计一个文本文件
words.txt
中每个单词出现的频率。你的脚本应当输出(以词频降序排列)
the 4
is 3
sunny 2
day 1
awk '{i=1;while($i!=""){array[$i]+=1;i++}}END{for (item in array) {print item,array[item] | "sort -r -n -k2"}}' words.txt
或 egrep -o "\b[[:alpha:]]+\b" $filename | awk '{count[$0]++}END{printf("%-14s%s\n,"word","Count");
for(ind in count){
printf("%-14%d\n",ind,count[ind])
}
}'
有效电话号码
- (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)
awk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt
转置文件
name age
alice 21
ryan 30
应当输出:
name alice ryan
age 21 30
awk '
{
for(i=1;i<=NF;i++){
array[NR,i]=$i
}
}
END{
for(i=1;i<=NF;i++){
for(j=1;j<=NR;j++){
if(j==NR)
printf array[j,i];
else
printf array[j,i]" "
}
print ""
}
}' file.txt
删除重复文件
ls -lS --time-style=long-iso | awk '
BEGIN{
getline; getline;
name1=$8; size=$5
}
{
name2=$8;
if (size==$5){
"md5sum" "name1" | getline; csum1=$1;
"md5sum" "name2" | getline; csum2=$1;
if ( csum1 == csum2 ){
print name1; print name2
}
}
size=$5; name1=name2;
}
' | sort -u > duplicate_files # 得到所有重复文件名的文件
cat duplicate_files | xargs -I {} md5sum {} | sort | uniq -w 32 | awk '{print $2}' | sort -u > unique_files # 在一组重复文件中取出一个特有文件作为独有文件存入
echo "removing..."
comm duplicate_files unique_files -3 | tee /dev/stderr | xargs rm # 删除所有在重复文件不在独有文件的文件,相当于每一组重复文件只保留一份
echo removed duplicates files successfully.
枚举文件类型信息
path=$1
declare -A statarray
while read
do
ftype=`file -b $line | cut -d, -f1` # 只显示文件类型
let statarray[$ftype]++;
done < <(find $path -type f -print) # 第一个< 用于重定向 第二个用于将子进程输出转换为相应的filename 文件名 加空格防止 解析为 <<
for ftype in "${!statarray[@]}";
do
echo $ftype: ${statarray["$ftype"]}
done
# Vim swap file: 1
# ASCII text: 1
查看目录
ls -d */
ls -F | grep "/$"
ls -l | grep "^d"
find . -type d -maxdepth 1 -print'''
压缩JS 丑化
cat example.txt | tr -d '\n\t' | tr -s ' ' | # 去掉空行 制表符 多余的空格
sed 's:/\*.*\*/::g' | # 去掉JS注释 /* content */
sed 's/ \?\([{}();,:]) \?\/1/g' # 去掉 {,} (,) ; 前后的空格
ping主机
for ip in 192.168.{1..255}
do
(
ping $ip -c 2 &> /dev/null
if [ $? -eq 0 ]
then
echo $ip is alive
fi
)& # ()中的命令会在子shell中执行 &放在后台
done
wait # 等待所有子进程结束
fping -a(显示所有活动主机ip) -u(显示不可达主机ip) -g(生成一组ip)
sed
- linux提供的一个外部命令,stream editor 行(流)式编辑器,非交互式的对文件进行增删改查
- 原理:一次处理文本中的一行 -> 存到缓存中 -> 处理完毕输出到屏幕
- 语法:sed [options] '{command}[flags]' [filename]
命令选项
-e script 将脚本指定的命令添加到处理输入时执行的命令中 多条件,一行中多个操作
echo abc | sed 's/a/A' | sed 's/c/C'
sed 's/a/A;s/c/C'
sed -e 's/a/A' -e 's/c/C'
echo 123 | sed -e "s|^|456|" # 456123 头部插入
-f script 将文件中指定的命令添加到处理输入时执行的命令中
-n 抑制自动输出
-i 编辑文件内容
-i.bak 修改文件时同时将原文件保存到.bak备份文件
-r 使用正则表达式
! 取反
内部命令
a 在匹配后面添加
i 在匹配前面添加
p 打印
d 删除
s 查找替换
c 更改
y 转换 N D P
flags
g 新文本替换现有文本的全部实例
p 打印原始内容
w filename 将替换的内容写入文件
双引号引用
text=hello
echo hello world | sed 's/$text/HELLO'
内部命令
- 追加操作
# 每一行后追加内容 append data "haha"
sed 'a\append data "haha"' data1
# 第二行后追加数据
sed '2a\append data "haha"' data1
# 第二到四行每行后新开一行追加数据
sed '2,4a\append data "haha"' data1
# 匹配字符串追加:找到3 the的行,在其后追加内容
sed '/3 the/a\append data "haha"' data1
- 插入操作
# 每一行后插入
sed 'i\insert data' data1
sed '2i\insert data' 第二行后插入
sed '/3 the/i\insert data'
- 替换操作 将一行中匹配到的内容替换为新的数据
# test替换为text
echo "this is a test" | sed 's/test/text/'
sed 's/dog/cat/' data1 每行的dog替换为cat
sed '2s/dog/cat/' data1
sed '2,4s/dog/cat/' data1
sed '/3 the/s/dog/cat' data1 将包含"3 the"的行中的dog替换为cat
- 替换 所有
sed 'c\change data' data1 将文件所有行替换为change data
sed '2c\change data'
sed '2,4c\change data' 替换2,3,4行
sed '/3 the/c\change data'
- 修改 字符转换
sed 'y/abc/ABC' data1 将data1中的a b c转换为对应的A B C字符
- 删除
sed 'd' data1 删除所有
sed '3d' data1 删除第三行
sed '3,4d' data1 删除3到4行
sed '/3 the/d' data1 删除所有满足匹配的行
sed '/^$/d' file # 删除文件中的空行
- 打印
sed 'p' data1 打印文件内容 每行会重复打印一遍 因为打印了一次 有奖读入缓存的数据打印了一次 就看到打印了两次
sed '3p' data1 第三行打印了两次 可以使用-n抑制内存输出
sed '3,4p'
sed '/3 the/p'
命令选项
-e 命令行中使用多个命令
sed -e 's/brown/green/;s/dog/cat/' data1
-f 从文件中读取编辑器命令
sed -f abc data1
-n 抑制内存输出
sed -n '2,$p' data1 打印文件的第二行到最后一行 不再输出两遍
-r 正则
sed -n -r '/^(3 the)/p' data1 打印文件中以3 the开头的行
-i 修改源文件
-i.bak 备份原文件后再修改源文件
语句
sed -n 's/.*<title>\(.*\)<\/title>.*<author><name>\([^<*]\)<\/name><email>\([^<*]\).*/From: \2 [\3]'
\nSubject: \1\n/p
sed -e 's/ *Rank-\([0-9]*\) *\([0-9]*\) *\(.*\)/\1\t\2'
sed "s,^/,$baseurl/," > tmp/$$.list
sed 's$</*[a-z]*>$$g' # 删除所有标签
标志
# 替换一行中的第二处为cat
sed 's/dog/cat/2' data
# 将一行中所有满足条件的都替换
sed 's/dog/cat/g' data
sed 's/this/THIS/2g' # 替换第二次出现的位置
# 打印文本内容 类似-p
sed '3s/dog/cat/p'
# w filename 将修改的内容存filename
sed '3s/dog/cat/w text' data 将修改的第三行的内容存入text
# &表示模式匹配到的字符串
echo this is example | sed 's/\w\+/[&]/g' # [this] [is] [example]
# \#代表括号内容匹配到的子串 \(pattern)\ 匹配子串
echo this is digit 7 | sed 's/digit \([0-9]\)/\1/' # this is 7
echo seven SEVEN | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1' # SEVEN seven
小技巧
$= 统计文本有多少行
sed -n '$=' data # 5
打印内容时加上行号
sed '=' data
案例
# DNS监控服务状态
sed -i '192.168.18.240/s/^/;/' /var/named/baidu.zone 将包含192.168.18.240的行的首位个空位加上;
sed -i '192.168.18.240/s/;//' 去掉;
sed -i 's/\b[0-9]\{3\}/NUMBER/g' data.txt # 将所有三位数字替换为NUMBER
删除文件中包含特定单词的句子
# 一个句子的组成:空格+文本+匹配字符+文本+句号
sed 's/ [^.]*mobile phone[^.]*\.//g' # [^.]* 表示不是.的任意字符,匹配多次