shell学习第一天

检查bash是否存在漏洞

[root@sf106232 ~]#

env x='() { :;}; echo be careful' bash -c "echo this is a test"

be careful
this is a test
出现be careful 表明存在漏洞.
修复漏洞方法:
yum -y update bash ##升级bash至最新版

关于vim

编写shell 的一些注视可以通过~./vimrc 设置。如
#!/bin/bash #选择shell 的解释器,也可以是#!/bin/sh或者#!/bin /env python
#date
#Auther :
#blog :
#description :
# version :
主要是为了让shell 看上去更规范.
在/etc/vimrc下追加如下内容:

function AddTitle()

call setline(1,"#!/bin/bash")
call append(1,"#*****************************************************")
call append(2,"#         Author: suixiaofeng")
call append(3,"#      blog:http://blog.cool360.org")
call append(4,"#          Email: [email protected] ")
call append(5,"#  " . "Last modified: " . strftime("%Y-%m-%d %H:%M"))
call append(6,"#       Filename: " . expand("%"))
call append(7,"#    Description: ")
call append(8,"#****************************************************")
endf
map  :call AddTitle():$o

然后写shell脚本的时候可以在开始的时候按F4 添加 一些自定义的注释文件。

相关上面的语法可以百度查找。

效果如下:vim 111.sh

#!/bin/bash
#*****************************************************
#         Author: suixiaofeng
#      blog:http://blog.cool360.org
#          Email: [email protected] 
#  Last modified: 2017-06-05 14:59
#       Filename: 111.sh
#    Description: 
#****************************************************

变量存放位置

env set declare 可以用来查看系统的一些变量。
declare -x NAME=test
export NAME=test
NAME=test ; export NAME
变量一般想永久生效就需要写在/etc/profile ~/.bash_profile ~/.bashrc /etc/bashrc 中,一般用大写字母写,如:export LANG="zn_CN.UTF-8" 让变量生效用 source

设置登录提示

cat /etc/motd
welcome to linux shell training.


方式二:
写成脚本的形式,在 /etc/profile.d下
cat /etc/profile.d/test.sh

echo "welcome to linux shell training."

unset消除变量

[root@sf106232 ~]# echo $USER
root
[root@sf106232 ~]# unset USER
[root@sf106232 ~]# echo $USER

变量引用

a=123456
b=123456
c=123456
引用:
a=123456-$a
结果:a=123456-123456
b='123456-$b'
结果为:
b=123456-$b

注:单引号里面是什么内容就输出什么,不区别变量。强引用

c="123456-$c"

结果:c=123456-123456

注:双引号,内容中又变量和命令会解析之后输出,比较适合场景:字符串中带有变量的需要解析之后输出的。

命令赋值给变量
方法一:
变量名=`ls`
方法二:
变量名=$(ls) #推荐

命令结果为变量赋值

CMD=$(date +%F)
tar zcf etc_$(date +%F).tar.gz /etc
结果:
[root@sf106232 ~]# ls etc_2017-06-07.tar.gz
etc_2017-06-07.tar.gz

A=$(uname -n) #主机名
tar zcf $A.tar.gz /tmp
结果:
[root@sf106232 ~]# ls sf106232.tar.gz
sf106232.tar.gz
变量后面接其他字符
$test-name 是错误的,$(test)-name是正确的。

awk中引用变量

[root@sf106232 ~]# ETT=test
[root@sf106232 ~]# awk 'BEGIN {print $ETT}'

[root@sf106232 ~]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@sf106232 ~]# awk 'BEGIN {print '$ETT'}'

[root@sf106232 ~]# awk 'BEGIN {print "'$ETT'"}' #正确操作
test
另一种引用方式:
[root@sf106232 ~]# ETT="test"
[root@sf106232 ~]# echo $ETT
test
[root@sf106232 ~]# echo "$ETT"
test
[root@sf106232 ~]# echo "$ETT" |awk '{print $0}'
test
[root@sf106232 ~]# echo '$ETT' |awk '{print $0}'
$ETT
[root@sf106232 ~]# echo $ETT |awk '{print $0}' #不推荐
test
[root@sf106232 ~]# echo $ETT |awk '{print $1}'
test

awk中$1 和$0区别

[root@sf106232 ~]# echo tets ttt |awk '{print $1}'
tets
[root@sf106232 ~]# echo tets ttt |awk '{print $0}'
tets ttt
注:awk中的$0是整行记录,$1,$2是FS分开的各个记录。

变量在sed中的应用

[root@sf106232 ~]# TTT=test
[root@sf106232 ~]# cat 1.log
test
st1
est2
[root@sf106232 ~]# sed -n /"$TTT"/p 1.log
test
[root@sf106232 ~]# sed -n /$TTT/p 1.log
test
[root@sf106232 ~]# sed -n /'$TTT'/p 1.log

shell脚本特殊重要的变量

$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。
$? 上个命令的退出状态,或函数的返回值。
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
例子:
[root@sf106232 ~]# cat 11.sh
#****************************************************
# Last modified: 2017-06-05 14:32
# Filename: 11.sh
# Description:
#****************************************************
echo $0
echo $1
echo $2
echo $#
echo $*
echo $@
#----------------------------
结果:
[root@sf106232 ~]# sh 11.sh hello world
11.sh
hello
world
2
hello world
hello world

位置参数大于9时必须写成$(参数)的形式

这个很强大 避免了手动输入的繁琐了。
[root@sf106202 webapps]# echo \${1..15}
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@sf106202 webapps]# echo \nihao{1..15}
nihao1 nihao2 nihao3 nihao4 nihao5 nihao6 nihao7 nihao8 nihao9 nihao10 nihao11 nihao12 nihao13 nihao14 nihao15

[root@sf106202 webapps]# echo \${1..15} > n.sh
[root@sf106202 webapps]# echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@sf106202 webapps]# sh n.sh {a..z}
a b c d e f g h i a0 a1 a2 a3 a4 a5标颜色的是 不能正确传参数的。
[root@sf106202 webapps]# cat n.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15} #这样是正确的
[root@sf106202 webapps]# sh n.sh {a..z}
a b c d e f g h i j k l m n o
[root@sf106202 webapps]#

dirname和bashname

dirname 可以打印脚本执行的时候的路径,basename打印脚本的名字

[root@sf106232 script]# dirname /u02/script/test.sh
/u02/script
[root@sf106232 script]# basename /u02/script/test.sh
test.sh
[root@sf106232 script]# cat test.sh
echo $0
dirname $0
basename $0
[root@sf106232 script]# sh /u02/script/test.sh
/u02/script/test.sh
/u02/script
test.sh
[root@sf106232 script]#

参数$#的应用

[root@sf106232 script]# cat t1.sh
#!/bin/bash
[ $# -ne 2 ] && {
echo "muse two args"
exit 1
}
echo hello,world

[root@sf106232 script]# sh t1.sh 1
muse two args
[root@sf106232 script]# sh t1.sh 1 2 ## 传参数两个符合,继续执行。
hello,world
[root@sf106232 script]# sh t1.sh 1 2 3
muse two args

参数$*和$@的应用

[root@sf106232 script]# set -- "woshi" sui xiaofeng ###通过set设置字符串参数,-- 表示重新设置参数变量。
[root@sf106232 script]# echo $#
3
[root@sf106232 script]# echo $1
woshi
[root@sf106232 script]# echo $2
sui
[root@sf106232 script]# echo $3
xiaofeng
[root@sf106232 script]# echo $*
woshi sui xiaofeng
[root@sf106232 script]# echo $@
woshi sui xiaofeng
[root@sf106232 script]# for i in $* ; do echo $i;done
woshi
sui
xiaofeng
[root@sf106232 script]# for i in $@ ; do echo $i;done
woshi
sui
xiaofeng

$#和$*的区别

[root@sf106232 script]# for i in "$@" ; do echo $i;done
woshi
sui
xiaofeng
[root@sf106232 script]# for i in "$*" ; do echo $i;done
woshi sui xiaofeng

shift移位(左移)

[root@sf106232 script]# set -- "wo shi" sui xiaofeng
[root@sf106232 script]# for i in $* ; do echo $i;done
wo
shi
sui
xiaofeng
[root@sf106232 script]# shift
[root@sf106232 script]# echo $#
2
[root@sf106232 script]# echo $1
sui

$?上一个命令的返回值

[root@sf106232 script]# cat test1.sh
[ $# -ne 2 ] && {
echo "must be two args."
exit 119 ##指定返回参数
}
echo test
[root@sf106232 script]# sh test1.sh
must be two args.
[root@sf106232 script]# echo $?
119
[root@sf106232 script]# sh test1.sh 111 222
test

$$获取当前执行的shell脚本进程号

$_ 获取上条命令的最后一个参数

$!获取上一条命令的进程号

echo命令的语法

echo参数选项
-n: 不换行输出内容
-e: 解析转义字符
转义字符:
\n: 换行
\r: 回车
\t: 制表符(tab)
\b: 退格
\v: 纵向制表符

换行:

方法一:
[root@sf106232 script]# echo -e "oldboy \n echo test"
oldboy
echo test
方法二;
[root@sf106232 script]# echo oldboy; echo test ;echo cccc;
oldboy
test
cccc

\t的使用

[root@sf106232 script]# echo -e "hello\tworld\nhello\tpython"
hello world
hello python

----------------
[root@sf106232 script]# printf "hello\tworld\nhello\tpython\nhello\tsdd\tsb\n"
hello world
hello python
hello sdd sb

\b退格

[root@sf106232 script]# echo -e "he\bllo"
hllo

exec

[root@sf106232 script]# seq 5 >tmp.log
[root@sf106232 script]# cat exec.sh
exec < ./tmp.log while read line do echo $line done echo ok [root@sf106232 script]# sh exec.sh 1 2 3 4 5 ok

shift:将位置参数左移

[root@sf106232 script]# cat n.sh
echo $1 $2
if [ $# -eq 2 ];then
shift
echo $1
fi
[root@sf106232 script]# sh n.sh 1 2
1 2
2

exit

退出shell,可以指定数位作为返回值。

shell变量子串

[root@sf106232 script]# TEST="hello world"
[root@sf106232 script]# echo ${TEST}
hello world
[root@sf106232 script]# echo $TEST
hello world
[root@sf106232 script]# echo ${#TEST} #变量名前加#可以返回变量值的长度。
11

另几种打印变量值的长度的方法

[root@sf106232 script]# echo $TEST|wc -L
13
[root@sf106232 script]# expr length "$TEST"
13
[root@sf106232 script]# echo "$TEST"|awk '{print length($0)}'
13

time命令

查看执行命令所需要的时间
[root@sf106232 script]# time ls
1.txt exec.sh n.sh t1.sh test1.sh test.sh tmp.log

real 0m0.011s
user 0m0.004s
sys 0m0.003s
[root@sf106232 script]#

变量中字符串的匹配

TEST=abcABC123ABCabc

字符串的截取

[root@sf106232 ~]# echo $TEST
abcABC123ABCabc
[root@sf106232 ~]# echo ${TEST:2}
cABC123ABCabc
[root@sf106232 ~]# echo ${TEST:2:2}
cA

#匹配最短匹配在变量中的使用

[root@sf106232 ~]# echo ${TEST#a*c} #从头开始匹配a然后删到c
ABC123ABCabc
[root@sf106232 ~]# echo ${TEST#a*C} #从头开始匹配a然后删到C
123ABCabc

#匹配最长匹配在变量中的使用

abcABC123ABCabc
[root@sf106232 ~]# echo ${TEST##a*C}
abc
[root@sf106232 ~]# echo ${TEST##a*c}

[root@sf106232 ~]#

变量结尾处开始最短匹配

[root@sf106232 ~]# echo ${TEST%a*C}
abcABC123ABCabc
[root@sf106232 ~]# echo ${TEST%a*c}
abcABC123ABC

变量结尾处开始最长匹配

[root@sf106232 ~]# echo ${TEST%%a*c}

[root@sf106232 ~]# echo ${TEST%%a*C}
abcABC123ABCabc
[root@sf106232 ~]#

匹配语法总结

# 表示从开始删除匹配最短
##表示从开始删除匹配最长
% 表示从结尾删除匹配最短
%%表示从结尾删除匹配最长

变量中字符的替换

[root@sf106232 ~]# echo $TEST
abcABC123ABCabc
[root@sf106232 ~]# echo ${TEST/abc/test}
testABC123ABCabc
[root@sf106232 ~]# echo ${TEST//abc/test}
testABC123ABCtest
[root@sf106232 ~]#

生产实例演示:
去掉n多文件共同的某一个特性
[root@sf106232 test]# for i in {1..7} ;do touch test_201706201_${i}_blog.cool360.org.txt ; done
[root@sf106232 test]# ll
total 0
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_1_blog.cool360.org.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_2_blog.cool360.org.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_3_blog.cool360.org.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_4_blog.cool360.org.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_5_blog.cool360.org.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_6_blog.cool360.org.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_7_blog.cool360.org.txt
去掉其中的blog.cool360.org
[root@sf106232 test]# for f in `ls *cool360*txt` ; do mv $f `echo ${f//_blog.cool360.org/}` ; done
[root@sf106232 test]# ll
total 0
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_1.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_2.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_3.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_4.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_5.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_6.txt
-rw-r--r-- 1 root root 0 Jun 20 15:49 test_201706201_7.txt

shell特殊扩展变量

判断变量是否已定义

[root@sf106232 test]# echo $test

[root@sf106232 test]# result=${test:-UNSET}
[root@sf106232 test]# echo $result ##test是空值的时候返回UNSET
UNSET

[root@sf106232 test]# test=test

[root@sf106232 test]# echo $test
test
[root@sf106232 test]# result=${test:-UNSET}
[root@sf106232 test]# echo $result ##test是有值的时候返回变量的值
test
[root@sf106232 test]#

${test:=UNSET}

[root@sf106232 test]# result=${test:=UNSET} ##判断test有没有值,没有值就给它赋值。
[root@sf106232 test]# echo $result
UNSET
[root@sf106232 test]# echo $test
UNSET
[root@sf106232 test]#

${test:?UNSET}

如果变量值未赋值或者为空值就UNSET字符串就被当做是标准错误输出。
[root@sf106232 test]# echo ${key:?not defined}
-bash: key: not defined
[root@sf106232 test]# echo ${key?not defined}
-bash: key: not defined
[root@sf106232 test]# key=1
[root@sf106232 test]# echo ${key?not defined}
1
[root@sf106232 test]# echo ${key:?not defined}
1
[root@sf106232 test]# unset key
[root@sf106232 test]# echo ${key:?not defined}
-bash: key: not defined
[root@sf106232 test]#

${test:+UNSET}

测试test1有没有值,有值就输出:+ 后面的值。
[root@sf106232 test]# test=${test1:+word}
[root@sf106232 test]# echo $test

[root@sf106232 test]# test1=11
[root@sf106232 test]# test=${test1:+word}
[root@sf106232 test]# echo $test
word

实例:

为了防止$path没有值的时候变成删除*,可以给他指定到/tmp
[root@sf106232 test]# echo $path

[root@sf106232 test]# sh -x del.sh
+ find /tmp -name '*.tar.gz' -type f -mtime +7
+ xargs rm -f
[root@sf106232 test]# cat del.sh
find ${path-/tmp} -name "*.tar.gz" -type f -mtime +7|xargs rm -f
这样可以防止误操作了。

猜你喜欢

转载自blog.csdn.net/sfdst/article/details/73998884