您的位置:首页 > 运维架构 > Shell

linux shell脚本编写

2016-11-28 11:42 423 查看
大家好

这是一篇自己阅读、学习的shell编程,工作中大量应用,尤为awk、sed、grep为主。希望对大家速成有用
可以直接翻看到中部位置
【data】
export PATH=/mall/jdk/jdk1.7/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
export LANG=zh_CN.GB18030

start=`date +%s -d "2011-11-28 15:55:37"`
end=`date +%s -d "2011-11-28 15:55:52"`
echo $(($end-$start))
date "+%Y-%m-%d %H:%M:%S"
date -d '+1 day' +"%d" 本日+1
date -s 20100405
date -s 14:31:00

1、上个月末
date -d `date +%y%m01`"-1 day" +%d
2、往前倒
date -d -`date +%d`day +%d
3、条件
if [`date +%d -d tomorrow` == 01 ];
4、上个月
date -d last-month
date -d -1month
date -d '-1 month' +"%m"
5、下个月
date -d next-month
date -d 1month
6、本月初
date -d 1`date +%B`
上个月初
date -d 1`date -d last-month +%B`
指定月份
day -d 1May

echo `date +%d` | xargs -I{} date -d '-{} day' +%Y%m%d Linux如何得到上月月末日期

sed -i "3s/.*/$table/g" conf/run.sql
table=t_sms_mt_log_`date +"%m"` 本月,然后月初1号还是统计上月
date -d '-1 day' +"%m" 本月,实实在在的本月
subject="每日验证码下发数量统计_`date -d '-1 day' +"%m%d"`"

select * from t_sys_user where user_code='duanzz';

update t_sys_user set terminal_id='13730000000' where user_code='duanzz';

set fileformat=unix

字符串的截取-替换
echo ${stringa:1} 从第二位一直往后所有
echo ${stringa:2:5} 从第三位往后一共截取5位

echo ${stringZ:(-4)} 从右到左开始截取
echo ${stringZ: -4} 从右到左开始截取,和上面效果一样
a=${stringa%%f} 去掉变量stringa后缀f。
echo ${stringZ/abc/xyz} 变量中字符串 abc被xyz替换
echo ${stringZ/#abc/XYZ} 用'XYZ'替换开头的'abc'.
echo ${stringZ/%abc/XYZ} 用'XYZ'替换结尾的'abc'.

you_id=${USER}-on-${HOSTNAME}
you_id=$USER\-on-$HOSTNAME
echo $you_id root-on-db1 效果一样。变量与字符串混合输出
val=${1##+(0)} # 使用局部变量, 匹配最长连续的一个或多个0.

引用:${backup_DIR}/$DATE
#备份的变量:
backup_dir=/home/mysql/mysql_bak
date=`date -d "+%Y%m%d %H:%M:%d"`
yes_time=`date -d yesterday "+%Y%m%d"`
mkdir -p /opt/chen$date\nailong chen20160608nailong
date -d "2 day ago" +"%Y-%m-%d" 昨天日期
date -d "1 week ago" +"%Y-%m-%d" 上周日期
date +%Y%m%d%h%M

单引号(' ')操作与双引号基本一样, 但是不允许引用变量, 因为$的特殊意义被关闭了. 在单引号中,
任何特殊字符都按照字面的意思进行解释, 除了'. 所以说单引号("全引用")是一种比双引号("部分引
用")更严格的引用方法.

'' 单引号屏蔽所有特殊字符
"" 双引号屏蔽部分特殊字符

【eval】

两次扫描

test.txt内容:hello shell world!

myfile="cat test.txt"

(1)echo $myfile  #result:cat test.txt

(2)eval echo $myfile  #result:hello shell world!

【echo】
echo -e 处理特殊字符,解释特殊字符。生效特殊字符
echo -n 不换行输出
echo -e "a\ndddd" //自动换行
echo $(ls -al)不换行 echo "$(ls -al)" 换行

bash$ echo hello\!
hello!
bash$ echo "hello\!"
hello\!
bash$ echo -e x\ty
xty
bash$ echo -e "x\ty"
x y

echo "chen" >> file :把chen内容追加到file文件中来,不覆盖
echo "chen" > file :覆盖了!!!

[A-Za-z0-9]

######################## (( ... ))结构可以用来计算并测试算术表达式的结果.
#!/bin/bash
((5 > 4))
echo $?
echo "Exit status of \"((5 > 4))\" is $?."

【从键盘输入-不止是read】
command << word
any input
word

read -p "Your command: " CMD
until [ $CMD == 'q' ]; do
! which $CMD && echo "Wrong command" && read -p "Input again:" CMD && continue
COMMAND=` which $CMD | grep -v "^alias" | grep -o "[^[:space:]]\{1,\}"`
bincp $COMMAND
echo "copy $COMMAND finished."
read -p "Continue: " CMD
done

【输出到屏幕上】
cat << word
-----------
name id
word
【脚本中调用】 source _function.sh
【shell函数】
hello ()
{
echo `date`
}
hello ###这儿直接写hello
`反引号允许你将shell命令的输出赋值给变量
today=`date +%Y%m%d`
echo "today is `date +%Y%m%d`"

sleep 5 #过五秒再执行

【basename】
$ basename /tmp/test/file.txt
file.txt
$ basename /tmp/test/file.txt .txt
file

【dirname】
dirname /var/log/messages 获取文件或文件夹的路径(上一级)
/var/log

【数组】
var=("123" "456" "789")
var[1]=123
var[2]=456
echo "$var[1],$var[2]"
#

echo $? 条件为真,输出0,条件为否,输出1
cp 1.txt /opt/apps/2.txt >/dev/null 2>&1
status=$?
echo $? #如果cp这个命令成功的话,输出0,不成功的话,输出1

:冒号在此是占位符,{str:=expr} 如果变量str不为空,${str:=expr}就等于str的值,若str为空,就把expr的值赋值给str
: >> target_file 如果这个文件之前并不存在, 那么就创建它
if [ $name="" ] 如果这个变量为空值
then : # 什么都不做,引出分支.
if [ ! -s 22.txt ] 如果22.txt这个文件为空
或者是 if [ -z 22.txt ]

[ $I -eq 1 ] && MIN=$MYRAND

if [ -s $name ] 如果这个变量为空
if [ -d $path ] 如果目录存在
if [ -s $path ] 如果目录存在
if [ -n "$1" ] # 测试是否有命令行参数(非空).
-a 文件存在 YES !
-f 这是一个一般文件
-d 这是一个目录
-b 这是一个快设备(软盘,硬盘,光驱等)
-c 这是一个字符设备(键盘,声卡等)
-p 这个文件是一个管道
-h 或者 -L 这是一个符号链接
-r 文件是否可读
-w 文件是否可写
-x 文件是否可执行
-O 你是否为文件拥有者
-G 文件group-id是否与你相同
f1 -nt f2 文件f1比文件f2新
f1 -ot f2 文件f1比文件f2旧

&&:and |:或者 !:非 command||comand ||:前者命令为真,后者才能执行,否则后者不执行
comand&&comand 前者为真,后者执行,前者为假,后者略过
sort:排序 wc:统计
cd /opt && ./1.txt :逐次执行的
【查找内存使用情况】
[root@db1 opt]# free -m|grep Mem|awk '{print "used\n----"};{print $3}'
used
----
985

【数值比较】
------------在 [ ] 中使用
-eq 数值相等。
-ne 数值不相等。
-gt 第一个数大于第二个数。
-lt 第一个数小于第二个数。
-le 第一个数小于等于第二个数。
-ge 第一个数大于等于第二个数。
------------在 (( )) 中使用
<= > < >=
----------字符串比较 = ==

小于, 按照ASCII字符进行排序
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
注意"<"使用在[ ]结构中的时候需要被转义.

-a 逻辑与 exp1 -a exp2 如果表达式exp1和exp2都为真的话, 那么结果为真.
-o 逻辑或 exp1 -o exp2 如果表达式exp1和exp2中至少有一个为真的话, 那么结果为真.
if [ "$exp1" -a "$exp2" ]

与(逻辑)
1 if [ $condition1 ] && [ $condition2 ]
2 # 与 if [ $condition1 -a $condition2 ] 相同
3 # 如果condition1和condition2都为true, 那结果就为true.
4
5 if [[ $condition1 && $condition2 ]] # 也可以.
6 # 注意: &&不允许出现在[ ... ]结构中.

或(逻辑)
1 if [ $condition1 ] || [ $condition2 ]
2 # 与 if [ $condition1 -o $condition2 ] 相同
3 # 如果condition1或condition2中的一个为true, 那么结果就为true.
4
5 if [[ $condition1 || $condition2 ]] # 也可以.
6 # 注意||操作符是不能够出现在[ ... ]结构中的.

【grep】
经常跟cat使用: cat /path/filename |grep [option]
grep -i 忽略大小写
grep -v "^#" file :grep -v "^#" filename 输出头字符不为#的行
grep -o 只显示匹配的字符串
grep --color 输出时,查找的关键字带颜色。
grep '[nN]*' test1.sh
grep -C 5 foo file 显示file文件里匹配foo字串那行以及上下5行
grep -B 5 foo file 显示foo及前5行
grep -A 5 foo file 显示foo及后5行

精准匹配 grep ':80\b' 只匹配到 :80
netstat -nat|grep ':80\>'
netstat -nat|grep ':80\b'
grep -E '123|abc' filename // 找出文件(filename)中包含123或者包含abc的行

【sed】

-r 支持正则表达式

sed -n '5p' filename 选择第5行输出
sed -n '/^\//p' /etc/fstab sed出以/开头的行并且print出来
sed '/^\/dev/d' fstab 查找以/dev开头的行删除
sed 's/^L/#/g' fstab_bak 把fstab_bak中L开头的行,把L换成# 加g表示全局替换

sed -n '/^\//a hello' /etc/fstab sed出以/开头的行并且随后追加一行:hello进去并且print出来,a的作用是追加,给文件追加内容
sed -n '/^\//a hello \n chen' /etc/fstab 再添加一行chen 这是给后面添加行,如果是前面添加 把a换位i

sed '3r /etc/fstab' fstab_bak 在fstab_bak的第三行处添加etc/fstab的内容进来
sed '/tmp/w /etc/tmp.txt' /etc/fstab 讲fstab有tmp的行保存在/etc/tmp.txt文件中来

sed '1,3d' /etc/fstab 删除第一行和第三行
sed '1,+2d' /etc/fstab 删除第一行以及以下两行
sed -e '8/p' -e 's/30/50/g' 1.txt 多个命令执行
sed '/^F/=' 1.txt 首字符为F的,并且输出他 的行号
sed '/chen/s/x/X/g' passwd 找到passwd中chen那一行,并且在那一行将x改为X
sed -n '/^#/!{/chen/p}' 11.txt 查找首字母不为#的且包含chen的行。打印出来
sed -i '/chen/{s/^#//g}' 11.txt 包含chen,并且首字符为#,去掉#。生效
sed -i '/^#/d' a.txt 去除空行
sed '/^chen/s/^chen.*/CHENNAILONG/' install.log 把chen开头的行整行替换为CHENNAILONG
sed -i "7s/.*/$table/g" conf/run.sql 把第七行替换为$table变量的值
sed 's/<!--/&chen/' 1.txt 在<!--后面追加 chen
\ 转译特殊字符
cat tomcat_running_state.txt |sed -r 's/\s+/\n/1' 第一个空格替换为换行

BASHUSERS=`echo $BASHUSERS | sed 's@[[:space:]]@,@g'`

xargs的默认命令是echo,这意味着通过管道传递给xargs的输入将会包含换行和空白,不过通过xargs的处理,换行和空白将被空格取代。

sed的后向引用;待研究
如果想sed命令生效 可加上-i

sed -f /path/script /etc/fstab 去这个目录选找script下面的所有脚本,对fstab进行处理

sed -i 's/^[[:space:]]//g' /etc/fastab 去fstab下,把行首的空格去掉 [[:space"]]+ 至少一个空格

【awk】

~ 匹配正则表达式 < 小于 ==不包含,必须等于
~!不匹配正则表达式 !== 不等于 &&两边都为真 |或者|| !非
awk '{print $1,$4}' fstab_bak awk出第一列与第四列
awk '{print $1"\t"$4}' fstab_bak awk出第一列与第四列,输出时候,中间加上空格
awk '{if($1~/devpts/)}print{$2}' fstab_bak 如果第一列出现devpts,这打印devpts的第二列内容
awk '{if($1~/devpts/)}print{ "good"}' fstab_bak 如果第一列出现devpts,这打印出good
awk '{if($1<$2)}{print $0}' fstab_bak 如果第一列中的数字小于第二列中的数字,输出这一行
awk '{$1~/^...a/}' fstab_bak 第一列中如果有第三字符为a的
awk '{$1~/tmpfs|proc/}' fstab_bak 第一列有tmpfs或者proc的,输出出来
awk -F "," '{print $2}' q.txt 以","为分隔符,找出第二段并且输出
awk '{name=$1;belts=$4;if(belts ~/yellow/)print name "is belt" belts}' grant.txt
awk '{if($1~"chen")($1="chennailong");print $1}' 1.txt 第一列中有chen出现,chen替换为chennailong
awk '{if($1~/chen/) {($1="chennailong");print $1}}' 1.txt 上条命令输出所有,多一对{}代表输出只修改那一行
awk '{if($1~/chen/){print $0}}' 1.txt
awk '{sum+=$2};{print sum}' 1.txt 统计第二列的总和
ls -al | awk ' /^[^d]/ {print $9"\t"$5} {tot+=$5} END {print "total KB:"tot}' 统计此目录下文件的文件名和长度,以及总和
awk 'BEGIN {split("123#456#789",myawk,"#")}' 给字段123#456#789切分,以#为分隔符
awk -F! '{print substr($3,6,11)}' 1.txt 截取以!为分隔符的第三段的第6字符以及包括第六字符往后11字符,如果只有6,那就是6个地附后往后这个行所有的了
awk 'sub(/chen/,"chen",$1)' 1.txt 截取第一段(默认分隔符为空格),含有chen的,替换为CHEN
awk 'BEGIN {ST="chen is a good boy"} END {print substr(ST,1,4)}' 1.txt 定义一个变量叫ST,然后使用substr截取第一字符以及包括第一字符往后4字符
awk 'BEGIN {ST=$1} END {print substr($1,1,4)}' 1.txt
awk 'BEGIN {ST=$1} END {print substr($1,1,4)}' 1.txt |sed '/ST/p
awk '{print length($0)}' 计算字符串长度
num=$(awk -F! '{print substr($3,6,11)}' 1.txt) 赋值。。。 有点意外吧
echo $num
awk '{print NR}' filename 统计一下此文件总共多少行
awk '{print NF}' filename 统计一下此文件总共多少域
awk '{if (NR > 0 && $4~/chen/) print$0}' filename 打印不为空行,并且第四列包含chen的行
awk -F: {'print $1'} /etc/passwd|tr "\n" " " #查找passwd里面的用户,这么多用户横向输出出来
echo $PWD |awk -F/ '{print $NF}' 显示其目录
awk -F '"' 特殊字符

who |awk '{if($1~/root/);print $1"\t""welcome"}'
who |awk '{print $1"\t""welcome"}'
【wc】
wc -l | file 计算行数
wc -w | file 计算文件中单词数
wc -c 。。。。字符数
【cut】
cut -b 3 :取第三列(无分隔符)
cat 1.txt |cut -d! -f1 以!为分隔符,切出第一段输出
cat 1.txt |cut -d! -f2-3 以!为分隔符,切出第一段与第三段输出
cut -c1 cut -c1-5 按照字符切割
【find】
find /etc -perm 777 -print
find /etc -type |xargs -exec ls -al {}\; -exec只用在find出文件时候使用
find -type f
find /etc -user chen -print
find /etc -size +1G -print.
find /etc -mtime -n(距今多少天) +n(多少天前)
find ./ -name "*.txt" -delete
find ./ -name "*.txt" |xargs rm -rf
find ./ -name "*.txt" -exec {} rm \;
【sort】
sort passwd 默认排序
sort -t passwd
sort -t: -k1 passwd 按照:分隔符排序,k1是表示第一域。表示按照用户名排序了。
sort -n -k 2 这是按照数字排序,表示按照第二列的数字排序
cat access.log |awk '{print $1}' |sort |uniq -c |sort -n -r |head -n 10
awk '{print $1}' access.log|sort | uniq -c |sort -n -k 1 -r|more
sort -u (去除重复行,排序) sort -r(降序) sort -r file.log -o file.log(排序后重定向)
sort -n number。log (字符型,升序排序)
【head】
head -n 10 一般经过排序后,统计选取前10 或者 head -10
tail -n 10 统计后10 tail -1000 acess.log
【uniq】
uniq -c 打印每一重复行的次数:基本上是统计ip什么的访问次数-----用的最多

uniq -d 只显示有重复数据行,并且重复行只显示其中一行

【脚本练习】-------【if else判断】
#!/bin/bash
echo "give Y is ok; gei N is no"
read choose
echo "your action is $choose"
if [ "$choose" == "Y" ]
then
echo "your choose is yes,thanks"
elif [ "$choose" == "N" ]
then
echo "your choose is no,we are sorry to you"
else
echo "take your answer in [Y]or
"
fi

【if】
if [ "$UID" -ne "$ROOT_UID" ] # 当然要使用root用户来运行. 下列为判断 不为root时候
if [ -n "$1" ] # 测试是否有命令行参数(非空).


if cd "$dir" 2>/dev/null; then # "2>/dev/null" 会隐藏错误信息.

与此相似, 在中括号中的条件判断也不一定非得要if不可, 也可以使用列表结构.
var1=20
var2=22
[ "$var1" -ne "$var2" ] && echo "$var1 is not equal to $var2"
home=/home/bozo
[ -d "$home" ] || echo "$home directory does not exist."

【expr】

用于整数值,也可用于字符串
expr 10 + 10 输出20
expr 30 / 3 输出10
expr 30 \* 3 输出90

【case】
case $name in
root) echo "welcome super user"
;;
chen) echo "welcome chen"
;;
*) echo "unknown words"
;;
esac
【for循环】
for $name in chen root ni #这里面是条件,如果什么满足什么
do
echo $name #如条件成立,则输出操作
done

for i in *.txt;do mv $i $(sed "s/txt/sh/" <<<$i);done 把所有txt文件改为sh文件
for I in {1..100}20.

【until】 until循环不断挂起,直至文件22.txt被删除,删除后,脚本进入正常状态
#!/bin/bash
file=/opt/22.txt
until [ ! -f $file ]

do

sleep 1
done
echo "file deleted"

【while】while简单循环 count小与5,则继续+1.档不满足小与5时。输出此时count的值
#!/bin/bash
count=0
while [ "$count" -lt 5 ]
do
count=`expr $count + 1`
echo $count
done

【split】文件有6行,切割为每2行为一个文件,一共切出3个文件。依次为xaa xab xac
split -2 a.txt

也可以 while read name 键盘输入

【tr】一般进行替换或者删除,进行字符转换
tr -s "[a-z]" < a.txt 表示去除重复字母 例如homeeeeee变为home
tr -s "[\012]" <a.txt 或者 tr -s "["\n"]" <a.txt 删除空行
tr -s "[a-z]" "[A-Z]" <a.txt 将小写转换为大写
tr -s "[chen]" "[chennailog]" <a.txt 将chen替换为chennailing

cat 201601.csv|awk -F ',' '{print $1}' |sort|uniq -c|sort -rn|awk '{if ($1>1);print $2}'|xargs -i grep {} 201601.csv

如果这一行的第一列=另外一行的第一列,输出这一整行

export TMOUT=0 终端永不超时,直接在上面 不会exit

ROOT_UID=0 # $UID为0的时候,用户才具有root用户的权限
LINES=50 # 默认的保存行数
E_XCD=66 # 不能修改目录?
E_NOTROOT=67 # 非root用户将以error退出
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux shell 脚本编写