Shell就是一种命令解析器
Shell也是一门编程语言,即shell脚本,shell是解释执行的脚本语言,可直接调用linux命令。
创建脚本
vi helloworld.sh #脚本以#!/bin/bash开头(指定解析器) #!/bin/bash echo "hello world" touch 1.txt 2.txt 3.txt ls -l > 1.txt
执行脚本
第一种方式 分配执行权 chmod u+x helloworld.sh ./helloworld.sh /mysh/helloworld.sh
第二种方式 可以没有执行权 bash helloworld.sh sh hellowrold.sh
使用set可以查看所有系统变量 BASH=/bin/bash HOME=/root HOSTNAME=linux01 JAVA_HOME=/opt/apps/jdk1.8.0_191 PATH=/usr/local/sbin:/usr/local
变量定义 变量名=变量值 #注意不能有空格 删除变量 unset 变量名 声明常量 readonly变量,不能使用unset变量 name=zss name=lss 改值 age=23 gender=M readonly USERNAME=Ly 不可变的变量 常量 取值 $name ${name} "$name" '$name' ---> $name的字符串 注意字符串的拼接 echo ${name} lss echo "$name"aaa lssaaa ""号中取变量的值可以正常取出 echos '$name'aaa $nameaaa ''号中取不出来变量的值 就是$name字符串 单引号会将所有特殊字符脱意 删除只读变量 (了解) yum -y install gdb cat << EOF|gdb attach $$ call unbind_variable("username") detach EOF unset username
export username=lisi 将变量的范围作用在所有的子bash中 source 将子bash定义的变量 作用在当前bash export 修饰的变量的作用域是 当前和所有的子进程 source 将子进程中的变量 拉取到当前
$1 $2 $n ${10} 接收单个参数 $* 接收所有参数 $@ 接收所有参数 $# 参数的个数 $? 接收上个命令执行的结果 0 执行成功 非0的是执行失败
接收单个参数 一直到$9都可以 10以上 ${10} vi args01.sh #!/bin/bash echo "接收的所有参数$1 $2 $3" touch $1 $2 $3 sh args01.sh 1.txt 2.txt 3.txt //自己增加部分 echo $1 $2 $3 $4 $10 [root@linux01 ~]# sh 1.sh 1 2 3 5 {10}
接收所有参数 $* 接收所有参数 $@ 接收所有参数 $# 参数的个数 $? 接收上个命令执行的结果 0 执行成功 非0的是执行失败 vi args02.sh #!/bin/bash echo "接收参数的个数$*" echo "接收参数的个数$#" touch $* #!/bin/bash echo "接收参数的个数$@" echo "接收参数的个数$#" touch $@ sh args02.sh 1.java 2.java
#!/bin/bash read -t 10 -p '请输入您的用户名:' username #username用来接收用户输入的用户名 -t 10代表10秒不输退出 read -t 10 -p '请输入您的密码:' password read -p "$1:" id //ID 自定义 echo "$username" echo "$password" echo "$id" //输出的是ID
expr 1+1 # 错误 1 + 1 之间必须有空格 expr 1 + 1 expr 1 + 1 \* 2 由于*有特殊含义 需要转义 expr `expr 1 + 2` \* 3 $((1+1)) $(((1+2)*3)) $[1+1] $[(1+2)*3] ${a} 取变量a的值 $() 取一个命令的结果 $(( )) 取算术运算表达式的运算结果 $[]相同
&&:用来执行条件成立后执行的命令 ||:用来执行条件不成立后的执行命令 ping windows && echo yes || echo no windows能ping通 输出yes 不能ping通输出no ls && echo yes || echo no ls执行成功 输出yes 执行不成功输出no
注意 符号 两边要有空格 test 1 = 1 && echo yes || echo no 1 == 1 test 1 != 1 && echo yes || echo no 1 != 1 test 1 -eq 1 && echo yes || echo no 1 == 1 test 1 -ne 1 && echo yes || echo no 1 != 1 test 1 -gt 2 && echo yes || echo no 1 > 2 test 1 -lt 2 && echo yes || echo no 1 < 2 test 1 -ge 2 && echo yes || echo no 1 >= 2 test 1 -le 2 && echo yes || echo no 1 <= 2 a=1 b=2 test $a = $b && echo yes || echo no test $a != $b && echo yes || echo no test $a && echo yes || echo no a存在 输出 yes 不存在输出 no -a 表示 and -o 表示 or //a 存在 并且 a=1 test $a -a $a = 1 && echo yes || echo no yes test $a -a $a = 2 && echo yes || echo no no //a 存在 或者 a=2 test $a -o $a = 2 && echo yes || echo no yes test命令通常做判断, test 命令和 [ ] 等同 #前后必须有空格 [1 = 1] && echo yes || echo no 错误 [ 1 = 1 ] && echo yes || echo no 正确
test "abc" == "bcd" && echo yes || echo no 判断字符串相等 注意 == 两边要有空格 test "abc" != "bcd" && echo yes || echo no 判断字符串不相同 判断字符串不是null test $abc && echo yes || echo no abc 存在 输出 yes 不存在输出 no 判断字符串是null test -z $abc && echo yes || echo no abc不存在 输出yes 存在输出 no [ $abc ] && echo yes || echo no 不是空 yes 是空 no if(name !=null ){ }
-d 判断是否是文件夹 -f 判断是否是文件 -L 判断是否是超链接 快捷方式 -e 判断是否存在 -r 判断是否有读权限 -w 判断是否有写权限 -x 判断是否是执行权 test -d 1.txt && echo yes || echo no [ -d 1.txt ] && echo yes || echo no [ -f 1.txt ] && echo yes || echo no [ -e 1.txt ] && echo yes || echo no [ -L /bin ] && echo yes || echo no [ -r 1.txt -a -w 1.txt ] && echo yes || echo no [ -x 1.txt ] && echo yes || echo no
单条件判断 if [ 条件 ] then 执行 fi 互斥条件判断 if [ 条件 ] then 程序 else 程序 fi #!/bin/bash read -p '请输入您的年龄:' AGE if [ $AGE -ge 18 ] then echo "你成年了可以看片了" else echo "你还未成年 滚蛋" fi #判断传入的参数 $1是否存在 存在打印值 不存在 则输出不存在 #!/bin/bash name=$1 if [ $name ] then echo "$name" else echo "name不存在" fi 多条件判断 if [ 条件1 ] then 执行 elif [ 条件2 ] then 执行 ... else 执行 fi #!/bin/bash if [ $1 -ge 90 -a $1 -le 100 ] then echo "优秀" elif [ $1 -ge 80 -a $1 -lt 90 ] then echo "良好" elif [ $1 -ge 60 -a $1 -lt 80 ] then echo "及格" elif [ $1 -ge 0 -a $1 -lt 60 ] then echo "潜力非常大" else echo "分数有误" fi
#!/bin/bash read -p '请输入一个数字(1-7):' NUM case $NUM in 1 ) echo "星期一" ;; 2 ) echo "星期二" ;; 3 ) echo "星期三" ;; 4 ) echo "星期四" ;; 5 ) echo "星期五" ;; 6 ) echo "星期六" ;; 7 ) echo "星期日" ;; * ) echo "你瞎啊" ;; esac
for (( 初始化表达式;布尔表达式;步进表达式 )) do 程序 done #!/bin/bash for (( i=0 ;i<=100;i++ )) do echo "$i" done #!/bin/bash sum=0 for(( i=0;i<=100;i++)) do sum=$[$sum+$i] done echo $sum for 变量 in 值1 值2 值3 do 程序 done 或者写成一行 for 变量 in 值1 值2 值3 ; do 程序 ; done #!/bin/bash for N in $* do echo $N done
for循环案例:在每台机器的根目录下 创建一个当前日期的文件夹 如果文件夹已存在则删除 创建 如果不存在则创建
#!/bin/bash for hostname in linux01 linux02 linux03 #linux0{1..3} `cat workers` do echo "连接$hostname" ssh $hostname "if [ -e /`date +%Y-%m-%d` ] then echo "先删除再创建" rm -rf /`date +%Y-%m-%d` mkdir /`date +%Y-%m-%d` else echo "直接创建文件夹" mkdir /`date +%Y-%m-%d` fi; exit" echo "退出$hostname" done vi workders linux01 linux02 linux03
猜数字小游戏 $RANDOM生成随机数 0-32767 #!/bin/bash g=$[ $RANDOM%100+1 ] for((;;)) do read -p '请输入您要猜的数字' NUM if [ $NUM == $g ] then echo '您猜对了' exit; else if [ $NUM -gt $g ] then echo '您猜大了' else echo '您猜小了' fi fi done
while [ 条件判断式 ] do 程序 ... done
#!/bin/bash num=1 while [ $num -le $1 ] do echo "$num" #num=$[$num+1] let num++ sleep 1 #睡眠1秒 done
定义数组 arr=(1 2 3 4 5 "abc"); 为数组元素赋值 arr[0]=100 arr[1]=200 根据指定索引获取元素 ${arr[索引]} 获取数组中所有元素 ${arr[*]} ${arr[@]} 获取数组的长度 ${#arr[*]} ${#arr[@]} 遍历数组 for n in ${arr[*]} do echo $n done 写成一行 for n in ${arr[*]};do echo $n;done 将脚本的输入参数转成一个数组 #!/bin/bash arr=($@) for n in ${arr[*]} do echo $n done
basename 命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。 basename /mysh/for.sh ---> for.sh basename -s .sh /mysh/for.sh ----->for 不显示后缀 basename /mysh ---> mysh basename -a /aaa/b.txt /ccc/d.txt -----> b.txt d.txt dirname 从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分) dirname /mysh/a.txt ---->/mysh dirname /mysh/1.txt /aaa/b.txt ----> /mysh /aaa
function 函数名(){ 函数体 return 返回值 } 注意: function可以省略不写 ()可以省略不写 但是函数名和{}之间要有空格 return可以结束函数 return默认返回最后一个命令的状态,也可以给定参数值 范围在 0-255 如果没有return 默认返回最后一个指令的退出状态值 $?
vi fn1.sh #!/bin/bash function hello(){ echo "hello" echo "world" } 调用方式 在当前shell脚本中调用 hello 在外界的bash中调用 source fn1.sh hello function mymkdir(){ echo "正在创建文件夹$1" mkdir $1; } 调用 mymkdir aaa function mymkdir(){ echo "正在创建文件夹$1" return echo "老子不创建了" mkdir $1; } #方法遇到return就结束 后面不执行了 function mymkdir(){ echo "正在创建文件夹$1" mkdir $1 #return 10 } 外界调用 source fn1.sh mymkdir aaa 创建成功 $? 返回 0 mymkdir 不传参数 创建失败 返回非0 加了return 10之后 无论成功还是失败 都是10
请用户输入信息 如果不输入一直提示 输入后 打印用户输入的信息 #!/bin/bash function userinput(){ input_var= output_var=$1 while [ -z $input_var ] do read -p "$output_var:" IN input_var=$IN done echo "$input_var" } userinput "请输入您的姓名"
crontab -e * * * * * 分 时 日 月 周 分:每小时的第几分 时:每天的第几时 0-24 日:每月的几号 月:每年的哪月 周:每周的第几天 * * * * * 代表每分钟 1 * * * * 每小时的01分执行 1 14 * * * 每天的14点01分执行 1 14 1 * * 每月1号的14点01分执行 1 14 2 7 * 每年7月2号的14点01分执行 1 14 * 7 2 每年7月的每周的第2天 14点01分执行 每周二至周五,下午6点 的计划任务 0 18 * * 2-5 (2,3,4,5) 1到10月份,每周二周五,下午6点的计划任务 0 18 * 1-10 2,5 12点和14点,检查apache服务是否启动 每年的1-3月7-9月 周一到周5 0 12,14 * 1-3,7-9 1-5 cat /var/spool/cron/root 查看错误信息
cut -d 指定切割方式 -f 第几列 文件名 vi cut.txt 001 liuyan 38 nv 002 tangyan 18 nv 003 jinlian 138 nv 004 dalang 8 nan cut -d " " -f 1 cut.txt 按照" "来切 显示第一列 001 002 003 004 cut -d " " -f 2,3 cut.txt 按照" "来切 显示2 3列 liuyan 38 tangyan 18 jinlian 138 dalang 8 #获取到柳岩的id cat cut.txt | grep liuyan 001 liuyan 38 nv cat cut.txt | grep liuyan | cut -d " " -f 1 001 echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/apps/jdk1.8.0_191/bin:/root/bin 选取系统PATH变量值,第2个“:”开始后的所有路径: echo $PATH | cut -d ":" -f 2- ifconfig ens33 | grep "inet "| cut -d "i" -f 2-|cut -d " " -f2
sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出
sed [选项参数] ‘command’ filename vi sed.txt 001 liuyan 38 nv 002 tangyan 18 nv 003 jinlian 138 nv 004 dalang 8 nan #显示的时候在第二行后插入 003 ximenqing 100 nan a 新增,a的后面可以接字串,在下一行出现 sed '2a 003 ximenqing 100 nan' sed.txt #删除包含001的记录 d 删除 sed '/001/d' sed.txt 查找替换 sed 's/要被取代的字串/新的字串/g' 文件名 #将所有00 替换成 "" sed 's/nv/女/g' sed.txt sed 's/0//g' sed.txt # 删除第二行 并将所有00 替换成"" -e同时执行多个指令 sed -e '2d' -e 's/0//g' sed.txt #显示时去除空行 sed '/^$/d' sed.txt #修改文件 -i 删除文件中所有空行 sed -i '/^$/d' sed.txt #给指定1-3行范围添加注释 sed -i '1,3s/^/#/g' sed.txt #将所有的注释删除 sed -i 's/^#//g' sed.txt #在001开头这一行下 加入 002 sed -i '/^001/a\002' sed.txt #在001开头这一行 上面 加入 0000 sed -i '/^001/i\0000' sed.txt 每一行之间都必须要以反斜杠 \ 来进行新行标记 a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行) i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行)
一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
awk [选项参数] ‘pattern1{action1} pattern2{action2}...’ filename pattern:表示AWK在数据中查找的内容,就是匹配模式 action:在找到匹配内容时所执行的一系列命令 -F 指定输入文件折分隔符 -v 赋值一个用户定义变量 vi awk.txt 001 liuyan 38 nv 002 tangyan 18 nv 003 jinlian 138 nv 004 dalang 8 nan #以空格进行切割 查找以001开头的所有行 打印第2列 awk -F " " '/^001/{print $2}' awk.txt #以空格进行切割 查找以001开头的所有行 打印第2列 第3列 用,分隔 awk -F " " '/^001/{print $2 "," $3}' awk.txt #在查找的内容之前打印 hello 在结尾打印 world awk -F " " 'BEGIN{print "hello"}/^001/{print $2 "," $3}END{print "world"}' awk.txt #给所有用户的年龄+10在输出 awk -F " " -v i=10 '{print $3+i}' awk.txt 内置变量 FILENAME 文件名 NR 已读的记录数 第几行 NF 浏览记录的域的个数(切割后,列的个数) 切割的列数 awk -F " " '{print FILENAME,NR,NF}' awk.txt #打印所有空行号 awk '/^$/{print NR}' awk.txt ip ifconfig ens33 | grep "inet " |awk -F " " '{print "ip地址是:"$2}'
sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出。
sort 参数 文件 -n 以数值的方式排序 不指定以字符串形式排序 1 11 111 2 22 -r 逆序 -t 指定分隔符 -k 指定列 vi sort.txt 001 liuyan 38 nv 002 tangyan 18 nv 003 jinlian 138 nv 004 dalang 8 nan sort -t " " -nk 3 sort.txt sort -t " " -nrk 3 sort.txt sort -t " " -nk 3 sort.txt >> 1.txt