如何再 AWK 中打印单引号
使用 \47
,例如:
seq 0 10 | awk '{print "partition by (pfield = \47"$1"\47"}'
批量执行命令
while read line ;
do
IP=$(取到 ip)
## 简单命令直接放到这里
ssh -n ${IP} ${cmd}
## 复杂的命令放到文件中
ssh -n ${IP} < ${cmd_file}
done < $file_path
-n 的作用是 ssh 不从标准输入读数据,而是从 /dev/null 中读数据。
while do done < $file 这种方式,会将所有的内容给 while 语句,如果 ssh 不加 -n , read 只能读到第一行的内容,剩余的内容会被 shh 读到,导致只能读一行的问题。
并行执行命令
cmd_file=$(mktemp -q /path/cmd_file.XXXXX)
if [ $? -ne 0 ]; then
echo "$0: Can not create"
exit 1
fi
while ..
do
echo "cmd string" >> ${cmd_file}
done
eval $(cat ${cmd_file})
1和2 append 到文件中
commad >> log.file 2>$1
单行处理管道中的数据
conmmad | \
while read line;
do
echo $line
done
read args1 args2 args3 ;
echo $args1
编辑文末 n 行
sed -e ":a " -e "$action ; N ; 2,n行数字ba" -e "P;D" file_path
找出不包含某个字符的文件
grep -L '字符串' ./文件名字
分割文件
# 每 1G 就分割一个文件
split -c 1G file pre_fix
cp 的升级版
rsync -av --exclude 排除某些文件
命令超时
timeout -- run a command with a time limit
SYNOPSIS
timeout [OPTION] DURATION COMMAND [ARG]..
DESCRIPTION
Start COMMAND, and kill it if still running after DURATION.
Mandatory arguments to long options are mandatory for short options too.
-k, --kill-after=DURATION
also send a KILL signal if COMMAND is still running
this long after the initial signal was sent
-s, --signal=SIGNAL
specify the signal to be sent on timeout;
SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals
拦截 hive 命令每次执行的命令
ps -ef | grep 'hive.beeline' | grep '\-f' | awk '{print $2}'
export data dictionary from hive
#!/bin/bash -x
function desc_dict(){
db=$1
tables=$(hive -e --showHeader=true " use $db ; show tables; " | sed "s/|//g ; s/[-+]//g ; s/tab_name//g" | xargs )
for table in $tables
do
echo "$db.${table//|/}" >> out.dict
hive -e --showHeader=true -e " use $db ; DESCRIBE ${table//|/} " >> out.dict
done
}
结合 python 在把 txt 文档转为 insert 语句或者其他的格式。https://gitee.com/bluedream_pp/pythonFirstInHead/blob/master/gen_data_dictionary_insert_sql.py
计算任务耗时
grep 'duration' ${filepath} | grep -v 'echo' | sed 's/-//g' | \
awk '{ {print $1 , $7}}' | sort -k2 -r -n | \
awk 'BEGIN{printf "%-28s,%5s\n","任务","耗时" } { printf "%-30s,%5s 秒\n",$1,$2}' >> ${filepath}
sed 批量执行命令
sed "s/\(.*\)/grep -o '\1' log.log /e" k.txt
文件路径
$> cat s.sh
#!/bin/bash -x
declare -r curr_dir=$(cd `dirname $0` ; pwd)
$> sh s.sh # 1
$> cd ..
$>sh folder/s.sh # 2
三个知识点:
basename 路径或者文件路径
:取出路径或者文件路径中除最后一个路径之前的相对路径。dirname 路径或者文件目录
:取出路径或者文件路径中最后一个路径。$0
是 shell 中的预定义的变量,意思是文件的相对路径。
例如,#1 中式当前目录是 .
,所以 basename $0
结果是s.sh
。dirname $0
的结果是 .
#2 中的往前推了一级目录,所以 basename $0
结果是s.sh
取 k-v 值
$>cat k-v.txt
1=tom
2=java
3=python
$> cat k-v.txt | sed -n '/[0-9]=tom/ s/[0-9]=\(.*\)/\1/p '
在命令行中添加代码块
sed -i -e '/^[sed|grep|cat|awk|ss|ifcofig|echo]/ i ```bash' -e '/^[sed|grep|cat|awk|ss|ifcofig|echo]/ a ```' linux_sed_awk_grep.md
正则查找分组内容
grep 'aaa:\(.*\)' t.txt | sed -n ' s/aaa:\(.*\)/\1/ ; p'
查看有哪些 sql 脚本在跑
ps -aux | grep org.apache.hive.beeline.BeeLine | awk ' $1="user_name" {print $0}' | grep .sql
awk 格式化输出
引用文章
当然也可以ask man
, 这里主要讲 awk 的内置函数 printf 的用法。
awk '{printf "%-11s,%12s",$1,$2}'
跑批工具函数
#功能描述:
# 1. 根据 shell 路径和参数执行任务
# 2. 如果遇到 exception 之类的问题,首先是重跑任务,然后是将错误(todo)信息到企业微信
# 3. 另外,todo: 增加捕捉异常的逻辑,思路是将根据当前的进程号找到该进程占用的日志文件,然后从日志文件中找出报错信息。
function run_hive(){
arguments=$*
echo $arguments
job_name=`echo $arguments | sed 's/.*-f\(.*\)\.sql.*/\1/g'`
count=0
# JOB执行失败重试过程,失败一分钟后重试
while [ 0 -eq 0 ]
do
echo ".................. ${job_name##*/} start at `date "+%Y-%m-%d %H:%M:%S" ` ..................."
hive ${arguments}
if [ $? -eq 0 ]; then
echo "--------------- ${job_name##*/} done at `date "+%Y-%m-%d %H:%M:%S" ` ---------------"
break;
else
# 执行失败,重试
count=$[${count}+1]
# 指定重试次数,重试超过3次即失败
if [ ${count} -eq 4 ]; then
alert_dw -t wework -g 预警消息群 -j ${job_name##*/} -m "${job_name##*/} retry 3 times , and failed" -o 3
exit 10
break
fi
echo "................${job_name##*/} after 60s retry .............."
sleep 60
fi
done
}
通过端口查看 hive 任务
ss -pnt src *:10000 | awk 'NR>1 {print $5}' | cut -d ":" -f2 | xargs -I{} lsof -i:{}
sed 替换
sed 的精确匹配: 's/\<store_cn\>/store_nm_cn/g'
sed 正在匹配后,单词大小转换:'s/正则表达式/\U&/g'(大写),'s/正则表达式/\L&/g'(小写)
sed 组匹配: 's/is_\(.*\)/\1_ind/g' 正则查找后,使用括号里面的内容替换,这个例子就是匹配以`is_`开头的单词,然后替换成使用括号里面的内容
+ `_ind` 替换。完成的功能就是将标识字段(is_xxx)转成 使用 _ind 结尾
查看批量任务执行状态
find ./recap_dm* -name 'log.log' | xargs lsof | awk '{if(NR>1){print $9}}' | uniq -c
执行最多的命令
history | grep 'git' | grep 'history' -v | awk '{$1="";print $0}' | sort | uniq -c | sort -r -k1 | head -10
截取日期
#!/bin/bash -x
index=$1
start_date=$2
#
rs=`hive --showHeader=false -e "
select
date_id_lyw_fd_wm
,date_id_lyw_ld_wm
,date_id_w_fd_wm
,date_id_w_ld_wm
from db.dim_date_d
where date_id = '${start_date}' "`
echo ${rs//[ +-]/}
echo ${rs//[ +-]/} | tr '|' ',' | awk -F',' 'BEGIN{} \
{for(i=1;i<=NF;i++){if((i-1)=="'$index'"){rs[i]=$i}}}\
END{for(ii in rs ) {print rs[ii]}}'
# 函数的形式
function get_date(){
index=$1
start_date=$2
rs=`hive --showHeader=false -e "
select
date_id_lyw_fd_wm
,date_id_lyw_ld_wm
,date_id_w_fd_wm
,date_id_w_ld_wm
from DB.dim_date
where date_id = '${start_date}' "`
ss=$(echo ${rs//[ +-]/} | tr '|' ',' | awk -F',' '{for(i=1;i<=NF;i++){if((i-1)=="'$index'"){rs[i]=$i}}} END{for(ii in rs ) {print rs[ii]}}')
echo $ss
return 0
}
v1=$(get_date 1 20200101)
echo $v1
这里需要注意的是 return 和 Java 中的 return 并不一样的,在 bash 中 return 返回的是函数退出时候的返回码,要想返回计算结果,需要使用 echo 命令。
去掉文本中的 BOM
utf-8 还有 utf-8 with bom 的格式,如果是这种格式的话,
在执行
hive -f file.sql 的时候,会报错。
单个文本的情况下,可以使用下面的方法:
使用 set nobomb 命令
:set nobomb
:x
批量更改的命令:
ls *.sql | xargs sed -i 's/\xef\xbb\xbf//g'
使用 presto 命令文件
grep -R 'presto-client' ./* | awk -F: -v OFS="---" '{print $1,$2}' | sed 's/--catalog.*//g; s/num=`//g' > ~/presto.txt
批量 explain
#!/bin/bash -x
sql_file_path=$1
out_file=$2
temp_path=$(mktemp -t -d explain_XXXXX)
cp -r $sql_file_path $temp_path/
cd $temp_path
find $temp_path -name '*.sql'
for file in `find $temp_path -name '*.sql'`
do
sed -i 's/\;/\n\;/g' $file
file_path=${file%/*}
cd ${file%/*}
csplit $file /\;/ -s {*} -n2 -f 'split' -b "%02d.sql"
for f in `ls $file_path/split*.sql`
do
sed -i "1i explain " $f
sed -i " s/\;//g" $f
if [ `grep "select" $f | wc -l` -gt 0 ]; then
if [ `grep "insert" $f | wc -l` -gt 0 ]; then
sed -i "1i set hive.exec.dynamic.partition.mode=nonstrict; " $f
fi
hive -f $f
fi
if [ "$?" -gt 0 ]; then
echo 'error $file' >> $out_file
fi
done
#exit 0
done
去除可见字符
sed -i " /^$/d ; s/[[:space:]]//g" split02.sql
--删除行首空格
sed 's/^[ \t]*//g'
删除历史的数据
find $curr_dir/ -name '*.txt' -ctime +7 -exec rm -f {} \;
UUID
cat /proc/sys/kernel/random/uuid
进程的管理
//https://www.cnblogs.com/itech/archive/2012/09/16/2687404.html
nohup command args // 忽略所有的hangup信号 ,ssh 后的 exit logout 断网都属于 hangup
setsid
jobs -l 查看后台进程
通过以下命令,我们可以对放入到后台的命令进行控制
查看当前终端下的后台进程:
直接执行:jobs
将查看到的某个后台进程放回到前台:
直接输入:fg {jobid} //这里的{jobid}是通过jobs命令中看到的进程前[]中的数字。
将当前正在前台运行的进程放到后台运行:
先敲下快捷键:ctrl +z //暂停当前正在运行的进程。
再执行:bg
终止当前正在前台运行的进程:
直接敲下快捷键:ctrl +c
disown亡羊补牢,为没有使用nohup与setsid的进程加上忽略HUP信号的功能。
使用方法:
将当前正在前台运行的进程放到后台运行(ctrl+z和bg);
然后执行disown -h %{jobid} //这里的{jobid}是通过jobs命令中看到的 进程前[]中的数字。
执行历史命令
!-{prefix-word}
例如:
!-his : 执行匹配的以 his 开头命令
sort 命令的应用
cat /etc/passwd | sort -k3 -t : | head -2
-k 是关键词,类比, -k1 --> order by 1
-t seperate , 例如 , -t : --> 使用 : 分割符号
不退出 .sh 文件,执行 .sh
1. shift + ;
2. :!bash -x %
3. :r !ls *.sql -- 取出当前目录下 sql 文件的名字放到当前行
其中 % 就是代表了当前的 shell 文件
如何生成临时文件
生成独一无二的文件名称的场景下,我们可以是使用 $$ 就可以了,例如 sed expression file > file$$
正如 shell 中,只要你想不到,没有做不到。 shell 有一个的维护临时文件的命令:
mktemp -[ d | t] sql_XXXXXX.sql
d:是临时目录
t:在系统默认的临时文件的路径写新建文件,一般是 /tmp/
XXXXX 是站位符,mktemp 会给我们自动生成几个符号
egrep 的应用
cat log.log | egrep '任务启动时刻|任务结束时刻|任务总计耗时|任务平均流量|记录写入速度|读出记录总数|读写失败总数' | xargs echo | awk '{print "\""$20"\",\""$23"\""}' | sed 's/"//g' | cut -d ',' -f 1
wordCount
[root@s4 ~]# cat d.txt
db.t1
db2.t2
aaa aaa
aaa
aaa
aaa
aaa
aaa
[root@s4 ~]# cat d.txt | tr ' ' '\n' | uniq -c
1 db.t1
1 db2.t2
7 aaa
cat work.txt
cat work.txt | tr ' ' '\n' | awk 'BEGIN{print "word","count"} \
{rs[$1]++} \
END{for(i in rs ){print i,rs[i]}}\
'
cat work.txt | awk 'BEGIN{print "word","count"} \
{for(i=0;i<=NF;i++){rs[$i]++}}
END{for(i in rs ){print i,rs[i]}}\
'
先整理一下 awk 的通用格式
awk [-f] [-F] [-v] [-FS] [-OFS] 'BEGIN{expresion} row_filter_regexp_expression {action} END{expression}'
BEGIN:在遍历每一行之前做的操作
END:遍历完每一行之后做的操作
row_filter_regexp_expression:使用正则表达式,或者逻辑表达式来过过滤行,相当于 where
{action} 处理里面的每一行,就会 select 一样
多行合并
sed ':a ; N;s/\n/ / ; t a ; ' file
通常的认为下面会 sed 会替换没一行上的回车,但是不会,如果要想替换回车,需要 tr '\n' ''
tr --> translate
[root@s4 ~]# cat d.txt | sed 's/\n//g '
db.t1
db2.t2
aaa
aaa
aaa
aaa
aaa
aaa
[root@s4 ~]# cat d.txt | sed ' N ;s/\n/,/g '
db.t1,db2.t2
aaa,aaa
aaa,aaa
aaa,aaa
[root@s4 ~]# cat d.txt | sed ':a ; N ;s/\n/,/g ; t a '
db.t1,db2.t2,aaa,aaa,aaa,aaa,aaa,aaa
最简单的:
cat d.txt | xargs
拼接 sql 语句中的 in ('A' ,'b')
>cat t.txt
A
b
>cat t.txt | awk '{print "'\''"$1"'\''"}' | sed ':a ; N ;s/\n/,/g ; t a '
'A','b'
使用 sed 替换,
为\t
cat file | sed "s#,#\t#g"
查看主机上所有的 git repository 已经状态
find ~ -name ".git" 2> /dev/null | sed 's/\/.git/\//g' | awk '{print "-------------------------\n\033[1;32mGit Repo:\033[0m " $1; system("git --git-dir="$1".git --work-tree="$1" status")}'
刷新历史数据的例子
// example.sh 20190501 20190531
// 数据从 20190501 刷新到 20190531
#!/bin/bash -x
start=${1:?please input start_date}
end=${2:?please input end_date}
i=0
while [ ${start} -le $end ]
do
bash -x wyf.sh $start
start=$(date -d " $start 1 day " +%Y-%m-%d)
i=$(($i+1))
done
// 传入的参数是 example.sh 1
// 这个意思是从从昨天,往前刷新 1 天的数据
#/bin/bash -x
for (( i = 1; i <= $1; i++ )); do
date=$(date -d"-$i day" +%Y-%m-%d)
echo $date
bash -x run_all.sh $date $date
done
#!/bin/bash -x
start=${1:?please input start_date}
end=${2:?please input end_date}
while [ `date -d ${start} +%s` -le `date -d "$end" +%s` ]
do
bash -x $3 $start
start=$(date -d"${start} 1 day" +%Y-%m-%d)
done
#!/bin/bash -x
start=${1:?please input start_date}
end=${2:?please input end_date}
order=$4
if [ $order = 'desc' ]; then
while [ `date -d ${start} +%s` -le `date -d "$end" +%s` ]
do
bash -x $3 $end
end=$(date -d"${end} -1 day" +%Y-%m-%d)
done
exit 0 ;
fi
while [ `date -d ${start} +%s` -le `date -d "$end" +%s` ]
do
bash -x $3 $start
start=$(date -d"${start} 1 day" +%Y-%m-%d)
done
show ip
ifconfig | awk '$1="inet" && $2 ~ /addr:[0-9]+/ {print $2}' | awk -F ':' ' $2 != "127.0.0.1" {print $2}'
ifconfig | awk '$1="inet" && $2 ~ /[0-9]{2,3}\.[0-9]{2,3}\.[0-9]{2,3}\.[0-9]{2,3}/ {print $2}'
show diretory like tree
ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
查看连接你服务器 top10 用户端的 IP 地址
netstat -nat | awk '{print $5}' | awk -F ':' '{print $1}' | sort | uniq -c | sort -rn | head -n 10
随机产生 32 的密码
tr -dc 'a-zA-Z0-9~!@#$%^&*_()+}{?></";.,[]=-' < /dev/urandom | fold -w 32 | head -n 1
多行数据合成一行
ls *.sh | awk '{print NR":/data/app/product/yc_data/workflow/biz/dm/deliver/dm_deliver/"$1}' | sed ':a;N;$!ba;s/\n/;/g'
取文本中的某个值
tail -100 his_out.log | grep '读出记录总数' | cut -d ':' -f 2 | sed s/' '//g
日期
#!/bin/bash -x
today=${1:-`date -d " -1 day " +%Y%m%d `}
## the first day of last month
first_day=$(date +%Y%m )01
## the first day of this month
last_month_first_day=$(date -d " -1 month" +%Y%m )01
## the fist day of the month` the first day
week=`date -d "$first_day" +%w`
if [ $week -eq 0 ] ; then
week=7
fi
((week--))
monday=`date -d " ${first_day} -${week} days" +%Y%m%d`
week=`date -d "$last_month_first_day " +%w`
if [ $week -eq 0 ] ; then
week=7
fi
((week--))
last_month_monday=`date -d " ${last_month_first_day} -${week} days" +%Y%m%d`
week=`date -d "$today" +%w`
if [ $week -eq 0 ] ; then
week=7
fi
((week--))
## 本周星期一的日期
monday=`date -d " ${today} -${week} days" +%Y%m%d`
## 本周星期日的日期
sunday=`date -d " ${monday} +6 days" +%Y%m%d`
## 上周星期一的日期
last_week_monday=`date -d " ${monday} -7 days" +%Y%m%d`
## 上周星期天的日期
last_week_sunday=`date -d " ${sunday} -7 days" +%Y%m%d`