静态语言:编译型语言
强类型(变量)
必须先编译完成后,才能使用
如:C、C++、JAVA、C#
动态语言:解释型语言
解释完一条就可以执行一条,边解释边执行
如:PHP、shell(面向过程)、python(面向对象)、perl
shell:弱类型编程语言


强类型:变量在使用前,必须实现声明,甚至还需要初始化
弱类型:变量用时声明




变量赋值:[set] VAR_NAME=VALUE,set通常省略


bash变量类型:
环境变量
本地变量(局部变量)
位置变量
特殊变量(系统变量)




本地变量:VAR_NAME=VALUE:整个bash进程
局部变量:local VAR_NAME=VALUE,作用域为当前代码段
环境变量:作用域为当前shell进场及其子进程
export VAR_NAME=VALUE "导出"
位置变量:$1,$2,...
特殊变量:$?(上一个命令的执行状态返回值)


程序执行,可能有两类返回值
1、程序执行结果
2、程序状态返回代码(0-255)
0:正确执行
1-255:错误执行,1,2,127系统预留
/dev/null:软件设备,bit bucket
eg:id student &> /dev/null,什么也不输出


撤销变量:
unset VAR_NAME


查看当前shell中变量(环境、本地变量):set
查看当前shell中环境变量:pringenv,env,export


脚本:命令的堆砌,按照实际需要,结合命令流程控制机制实现的源程序


#!/bin/bash(可执行执行的路径) --》shebang,魔数 


如何执行脚本?
1、将脚本的权限改为可执行,然后直接写脚本名执行
2、bash 脚本名


注意:
脚本在执行时会启动一个当前shell的一个子shell进程,如果是命令行中启动的脚本会
继承当前shell环境变量,如果是系统自动执行的脚本(非命令行启动,另外登陆一个shell)就需要自我定义
需要各环境变量

引用变量:${VAR_NAME},{}通常可以省略,但有时不可以省略

bash写脚本编译java项目 linux中bash脚本编程_bash写脚本编译java项目

bash中如何实现条件判断?
条件测试类型:
正数测试
字符测试
文件测试
条件测试的表达式:
[ expression ]
[[ expression ]]
test expression
正数比较:
-eq:测试两个正数是否相等:$A -eq $B
-ne:测试两个正数是否不等
-gt:>
-lt:<
-ge:>=
le:<=
命令间的逻辑关系:
逻辑与:&&
逻辑或:||
eg:如果用户不存,就添加,否则,显示其已经存在
! id user1 && useradd user1 || echo "user1 exists"

bash写脚本编译java项目 linux中bash脚本编程_sed_02

这样写不太方便,shell提供了专门的条件判断结构

if 判断条件;then
statement1
statement2
...
 fi




 if 判断条件;then
   statement1
 else
statement2
 fi




 if 判断条件;then
statement1
..
 elif 判断条件2;then
statement2
...
 else
statement3
...
 fi



 NAME=user1
 if [ id $NAME ];then
echo "admin"
 else
echo "common users"
 fi





练习,写一个脚本,完成以下要求:
1、添加3个用户user1, user2, user3;但要先判断用户是否存在,不存在而后再添加;
2、添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;
3、最后显示当前系统上共有多少个用户;






练习,写一个脚本,完成以下要求:
给定一个用户:
1、如果其UID为0,就显示此为管理员;
2、否则,就显示其为普通用户;


如果 UID为0;那么
  显示为管理员
否则
  显示为普通用户

NAME=user16
 USERID=`id -u $NAME`
 if [ $USERID -eq 0 ]; then
   echo "Admin"
 else
   echo "common user."
 fi






 NAME=user16
 if [ `id -u $NAME` -eq 0 ]; then
   echo "Admin"
 else
   echo "common user."
 fi




 if id $NAME; then


  
练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
   如果有,就显示有多少个这类用户;否则,就显示没有这类用户;

grep "bash$" /etc/passwd &> /dev/null
 RETVAL=$?
 if [ $RETVAL -eq 0 ]; then
    
 if grep "bash$" /etc/passwd &> /dev/null; then



提示:“引用”一个命令的执行结果,要使用命令引用;比如: RESAULTS=`wc -l /etc/passwd | cut -d: -f1`;
      使用一个命令的执行状态结果,要直接执行此命令,一定不能引用;比如: if id user1一句中的id命令就一定不能加引号;
 如果想把一个命令的执行结果赋值给某变量,要使用命令引用,比如USERID=`id -u user1`;
      如果想把一个命令的执行状态结果保存下来,并作为命令执行成功与否的判断条件,则需要先执行此命令,而后引用其状态结果,如
id -u user1
RETVAL=$?
此句绝对不可以写为RETVAL=`id -u user1`;


练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
   如果有,就显示其中一个的用户名;否则,就显示没有这类用户;


练习:写一个脚本
给定一个文件,比如/etc/inittab
判断这个文件中是否有空白行;
如果有,则显示其空白行数;否则,显示没有空白行。

#!/bin/bash
 A=`grep '^$' /etc/inittab | wc -l`
 if [ $A -gt 0 ]; then
  echo "$A"
 else
  echo "meiyoukongbaihang"
 fi
                  —— by 张帅
 
 #!/bin/bash
 FILE=/etc/inittab
 if [ ! -e $FILE ]; then
   echo "No $FILE."
   exit 8
 fi


 if grep "^$" $FILE &> /dev/null; then
   echo "Total blank lines: `grep "^$" $FILE | wc -l`."
 else
   echo "No blank line."
 fi



练习:写一个脚本
给定一个用户,判断其UID与GID是否一样
如果一样,就显示此用户为“good guy”;否则,就显示此用户为“bad guy”。

#!/bin/bash
 USERNAME=user1
 USERID=`id -u $USERNAME`
 GROUPID=`id -g $USERNAME`
 if [ $USERID -eq $GROUPID ]; then
   echo "Good guy."
 else
   echo "Bad guy."
 fi




进一步要求:不使用id命令获得其id号;


#!/bin/bash
 #
 USERNAME=user1
 if ! grep "^$USERNAME\>" /etc/passwd &> /dev/null; then
   echo "No such user: $USERNAME."
   exit 1
 fi


 USERID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f3`
 GROUPID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f4`
 if [ $USERID -eq $GROUPID ]; then
   echo "Good guy."
 else
   echo "Bad guy."
 fi













练习:写一个脚本
给定一个用户,获取其密码警告期限;
而后判断用户密码使用期限是否已经小于警告期限;
提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限;

如果小于,则显示“Warning”;否则,就显示“OK”。


圆整:丢弃小数点后的所有内容


#!/bin/bash
 W=`grep "student" /etc/shadow | cut -d: -f6`
 S=`date +%s`
 T=`expr $S/86400`
 L=`grep "^student" /etc/shadow | cut -d: -f5`
 N=`grep "^student" /etc/shadow | cut -d: -f3`
 SY=$[$L-$[$T-$N]]


 if [ $SY -lt $W ]; then
   echo 'Warning'
 else
   echo 'OK'
 fi




—— by 董利东
shell中如何进行算术运算:
A=3
B=6
1、let 算术运算表达式
let C=$A+$B
2、$[算术运算表达式]
C=$[$A+$B]
3、$((算术运算表达式))
C=$(($A+$B))
4、expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
C=`expr $A + $B`








测试方法:

[ expression ]
 [[ expression ]]
 test expression




bash中常用的条件测试有三种:
整数测试:

-gt
-le
-ne
-eq
-ge
-lt


 INT1=63
 INT2=77
 [ $INT1 -eq $INI2 ]
 [[ $INT1 -eq $INT2 ]]
 test $INT1 -eq $INT2



if grep "^$USERNAME\>" /etc/passwd ;then
注意:这里的条件判断没有加[],if可以自动的判定命令执行完成后的
返回状态码,如果是0就表示执行成功,然后执行then


文件测试:
-e FILE:测试文件是否存在
-f FILE:测试文件是否为普通文件
-d FILE:测试指定路径是否为目录
-r FILE: 测试当前用户对指定文件是否有读取权限;
-w 
-x


定义脚本退出状态码


exit: 退出脚本
exit #
如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码;



if [ -e /etc/passwd ];then




测试脚本是否有语法错误:
bash -n 文件
bash -x 脚本:单步执行


bash命令的类型:
本地变量(局部变量)
环境变量
位置变量:

$1,$2,...(在脚本中引用我们输入的变量)
shift:参数切换
 shift的用法:

bash写脚本编译java项目 linux中bash脚本编程_bash写脚本编译java项目_03

特殊变量:

$?:上一条命令的退出命令码
$#:参数的个数(下面的红色就是2个参数)
$*:参数列表
$@:参数列表
 #执行脚本
 ./first.sh /etc/passwd /etc/inittab 
 $1:/etc/passwd
 $2:/etc/inittab



练习:写一个脚本
给脚本传递两个参数(整数);
显示此两者之和,之乘积;

#!/bin/bash
 #
 if [ $# -lt 2 ]; then
   echo "Usage: cacl.sh ARG1 ARG2"
   exit 8
 fi


 echo "The sum is: $[$1+$2]."
 echo "The prod is: $[$1*$2]."






必须要学好的三个文本处理工具
grep,sed(流编辑器),awk


sed基本用法:
sed:Stream  EDitor

bash写脚本编译java项目 linux中bash脚本编程_linux_04

默认不编辑原文件,仅对模式空间中的数据做处理,而后,处理结束后,将模式空间打印至屏幕
sed [options] 'AddressCommand' file ...
-n: 静默模式,不再默认显示模式空间中的内容
-i: 直接修改原文件
-e SCRIPT -e SCRIPT:可以同时执行多个脚本,就是AddressCommand
-f /PATH/TO/SED_SCRIPT,从文件中读取脚本(脚本写在scripts文件中,一个一个读取然后对file进行处理)
sed -f /path/to/scripts  file
-r: 表示使用扩展正则表达式

Address:
1、StartLine,EndLine
比如1,100
$:最后一行
2、/RegExp/
/^root/
3、/pattern1/,/pattern2/
第一次被pattern1匹配到的行开始,至第一次被pattern2匹配到的行结束,这中间的所有行
4、LineNumber
指定的行
5、StartLine, +N
从startLine开始,向后的N行;

Command:
d: 删除符合条件的行;
p: 打印命令,显示符合条件的行;注意:这会重复打印两次,因为sed默认会打印模式空间中的内容,可以在前面加上-n
a \string: 在指定的行后面追加新行,内容为string
\n:可以用于换行
i \string: 在指定的行前面添加新行,内容为string
r FILE: 将指定的文件的内容添加至符合条件的行处
w FILE: 将地址指定的范围内的行另存至指定的文件中; 
s/pattern/string/修饰符: 查找并替换,默认只替换每行中第一次被模式匹配到的字符串(替换的是字符串而不是整行)
加修饰符
g: 全局替换,(整行被匹配的字符串全部都要替换)
i: 忽略字符大小写
s///: s###, s@@@(可以使用这样的字符来替换前面的/,功能一样)
eg:sed 's@/@#@' /etc/fstab
将/替换为#
grep里的后向引用:\(\), \1, \2在这里同样使用

l..e:  like-->liker
 love-->lover


 
 

&: 引用模式匹配整个串

eg:sed 's#l..e#&r#' sed.txt
  sed 's#\(l..e\)#\1r#g' sed.txt


 like-->Like
 love-->Love
eg:sed 's#l\(..e\)#L\1#g' sed.txt


可以不匹配整个串


sed练习:
1、删除/etc/grub.conf文件中行首的空白符;
sed -r 's@^[[:spapce:]]+@@g' /etc/grub.conf
2、替换/etc/inittab文件中"id:3:initdefault:"一行中的数字为5;
sed 's@\(id:\)[0-9]\(:initdefault:\)@\15\2@g' /etc/inittab
3、删除/etc/inittab文件中的空白行;
sed '/^$/d' /etc/inittab
4、删除/etc/inittab文件中开头的#号; 
sed 's@^#@@g' /etc/inittab
5、删除某文件中开头的#号及后面的空白字符,但要求#号后面必须有空白字符;
sed -r 's@^#[[:space:]]+@@g' /etc/inittab
6、删除某文件中以空白字符后面跟#类的行中的开头的空白字符及#
sed -r 's@^[[:space:]]+#@@g' /etc/inittab
7、取出一个文件路径的目录名称;
echo "/etc/rc.d/" | sed -r 's@^(/.*/)[^/]+/?@\1@g'
文件名:
echo "/etc/rc.d/" | sed -r 's@^/.*/([^/]+)/?@\1@g'




字符测试:
==:测试是否相等,相等为真,不等为假
!=: 测试是否不等,不等为真,等为假
>
<
-n string: 测试指定字符串是否为空,空则真,不空则假
-z string: 测试指定字符串是否不空,不空为真,空则为假


eg:

A=hello
 B=hi
 [[ "$A" == "$B" ]]


看清用法,==两边也有空格,一个=也行,但也要有空格


练习:
传递三个参数给脚本,第一个为整数,第二个为算术运算符,第三个为整数,将计算结果显示出来,要求保留两位精度。形如:
./calc.sh 5 / 2


eg:

echo "scale=2;100/22;" | bc
bc <<< "scale=2;111/22;" 特殊用法








循环结构:
1、for
for 变量 in 列表;do(如果do写在下一行就不用在前面加;)
循环体
done
如何生成列表?

{1..100} 
 `seq [起始数[步进长度]] 结束数` 
 2、while
 3、until






declare -i SUM=0
integer
-x声明为环境变量



写一个脚本:
1、设定变量FILE的值为/etc/passwd
2、依次向/etc/passwd中的每个用户问好,并显示对方的shell,形如:  
Hello, root, your shell: /bin/bash
3、统计一共有多少个用户


for I in `seq 1 $LINES`; do echo "Hello, `head -n $I /etc/passwd | tail -1 | cut -d: -f1`"; done






测试:
1、整数测试
2、字符测试
3、文件测试
组合测试条件
-a:与关系
-o:或关系
!:非关系
if [ $# -gt 1 -a $# -le 3 ]
if [ $# -gt 1 ] && [ $# -le 3 ]












写一个脚本,利用RANDOM生成10个随机数,并找出其中的最大值,和最小值;

#!/bin/bash
 #
 declare -i MAX=0
 declare -i MIN=0


 for I in {1..10}; do
   MYRAND=$RANDOM
   [ $I -eq 1 ] && MIN=$MYRAND
   if [ $I -le 9 ]; then
     echo -n "$MYRAND,"
   else
     echo "$MYRAND"
   fi
   [ $MYRAND -gt $MAX ] && MAX=$MYRAND
   [ $MYRAND -lt $MIN ] && MIN=$MYRAND
 done


 echo $MAX, $MIN





面向过程
控制结构
顺序结构
选择结构
循环结构


选择结构:
if: 单分支、双分支、多分支

if CONDITION; then
   statement
   ...
 fi


 if CONDITION; then
   statement
   ...
 else
   statement
   ...
 fi


 if CONDITION1; then
   statement
   ...
 elif CONDITION2; then
   statement
   ...
 esle
   statement
   ...
 fi










case语句:选择结构


case SWITCH in 
 value1)
   statement
   ...
   ;;
 value2)
   statement
   ...
   ;;
 *)
   statement
   ...
   ;;
 esac






eg:

case $1 in 
 [0-9])
echo "it's a digist"
 ;;
 [a-z])
echo "is's a char"
 ;;
 *)
echo "it's others"
 ;;
 esac





#!/bin/bash
 #
 DEBUG=0
 ADD=0
 DEL=0


 for I in `seq 0 $#`; do
   if [ $# -gt 0 ]; then
 case $1 in
 -v|--verbose)
DEBUG=1
shift ;;  ###将刚刚引用的变量踢掉,下一个就变成了第一个参数
 -h|--help)
echo "Usage: `basename $0` --add USER_LIST --del USER_LIST -v|--verbose -h|--help"
exit 0
;;
 --add)
ADD=1
ADDUSERS=$2
shift 2
;;
 --del)
DEL=1
DELUSERS=$2
shift 2
;;
 *)
echo "Usage: `basename $0` --add USER_LIST --del USER_LIST -v|--verbose -h|--help"
exit 7
;;
     esac
   fi
 done


 if [ $ADD -eq 1 ]; then
   for USER in `echo $ADDUSERS | sed 's@,@ @g'`; do
     if id $USER &> /dev/null; then
       [ $DEBUG -eq 1 ] && echo "$USER exists."
     else
       useradd $USER
       [ $DEBUG -eq 1 ] && echo "Add user $USER finished."
     fi
   done
 fi


 if [ $DEL -eq 1 ]; then
   for USER in `echo $DELUSERS | sed 's@,@ @g'`; do
     if id $USER &> /dev/null; then
       userdel -r $USER
       [ $DEBUG -eq 1 ] && echo "Delete $USER finished."
     else
       [ $DEBUG -eq 1 ] && echo "$USER not exist."
     fi
   done
 fi







练习:写一个脚本showlogged.sh,其用法格式为:
showlogged.sh -v -c -h|--help
其中,-h选项只能单独使用,用于显示帮助信息;-c选项时,显示当前系统上登录的所有用户数;如果同时使用了-v选项,则既显示同时登录的用户数,又显示登录的用户的相关信息;如
Logged users: 4. 

They are:
 root     tty2         Feb 18 02:41
 root     pts/1        Mar  8 08:36 (172.16.100.177)
 root     pts/5        Mar  8 07:56 (172.16.100.177)
 hadoop   pts/6        Mar  8 09:16 (172.16.100.177)


 #!/bin/bash
 #
 declare -i SHOWNUM=0
 declare -i SHOWUSERS=0


 for I in `seq 1 $#`; do
   if [ $# -gt 0 ]; then
     case $1 in
     -h|--help)
       echo "Usage: `basename $0` -h|--help -c|--count -v|--verbose"
       exit 0 ;;
     -v|--verbose)
       let SHOWUSERS=1
       shift ;;
     -c|--count)
       let SHOWNUM=1
       shift ;;
     *)
       echo "Usage: `basename $0` -h|--help -c|--count -v|--verbose"
       exit 8 ;;
     esac
   fi
 done


 if [ $SHOWNUM -eq 1 ]; then
   echo "Logged users: `who | wc -l`."
   if [ $SHOWUSERS -eq 1 ]; then
     echo "They are:"
     who
   fi
 fi