bash

引用:

双引号弱引用,参数扩展

单引号强引用,不可嵌套

花括号扩展不能被引用

命令执行前字符串删除引用符号

[root@node01 ~]# dengchao=goodman
[root@node01 ~]# echo "$dengchao"
goodman

bash解释时首先读到双引号时,会把它当作一个单词不会进行空格分割
再把其中的变量替换为值,最后再去掉双引号

[root@node01 ~]# echo '$dengchao'
$dengchao
单引号就不会对其中的变量做解释,而是字符本来的状态

命令替换:

反引号:`ls -l /`

$(       ):$(ls /)

              可以嵌套

[root@node01 ~]# ls `echo /`
bin   dev  home  lib64       media  opt   root  selinux  sys  usr
boot  etc  lib   lost+found  mnt    proc  sbin  srv      tmp  var
[root@node01 ~]# echo `ls /`
bin boot dev etc home lib lib64 lost+found media mnt opt proc root sbin selinux srv sys tmp usr var

当用反引号把字符串引起来的时候,bash会去先解释这段字符串,
做词的拆分,然后再执行命令,把命令执行完的结果替换掉这段字符串

[root@node01 ~]# ls $(echo /)
bin   dev  home  lib64       media  opt   root  selinux  sys  usr
boot  etc  lib   lost+found  mnt    proc  sbin  srv      tmp  var

[root@node01 ~]# ls $(echo $(echo /))
bin   dev  home  lib64       media  opt   root  selinux  sys  usr
boot  etc  lib   lost+found  mnt    proc  sbin  srv      tmp  var

$( )可以命令嵌套

退出状态:

$?

[root@node01 ~]# ls /
bin   dev  home  lib64       media  opt   root  selinux  sys  usr
boot  etc  lib   lost+found  mnt    proc  sbin  srv      tmp  var
[root@node01 ~]# echo $?
0
输出 说明程序执行 OK,正常退出

[root@node01 ~]# ls /noexists
ls: cannot access /noexists: No such file or directory
[root@node01 ~]# echo $?
2

输出 非零 说明程序执行 失败

逻辑判断:

command1 && command2

command1 || command2

[root@node01 ~]# ls /noexists || echo "程序执行失败,该文件夹不存"
ls: cannot access /noexists: No such file or directory
程序执行失败,该文件夹不存
[root@node01 ~]# ls /noexists 2> /dev/null || echo "程序执行失败,该文件夹不存"
程序执行失败,该文件夹不存

shell中逻辑判断与c语言中相反
true
非0: false
与c语言中正数代表true相反

算术表达式:

let  算术运算表达式

        let C=$A+$B

[root@node01 ~]# a=1
[root@node01 ~]# b=2
[root@node01 ~]# let c=$a+$b
[root@node01 ~]# echo $c
3
[root@node01 ~]# let c=$a+$b
[root@node01 ~]# echo $?
0
[root@node01 ~]# let c=0
[root@node01 ~]# echo $?
1

$[算术表达式]

                C=$[$A+$B]

[root@node01 ~]# a=1
[root@node01 ~]# b=2
[root@node01 ~]# c=$a+$b
[root@node01 ~]# echo $c
1+2
[root@node01 ~]# c=$[$a+$b]
[root@node01 ~]# echo $c
3

$((算术表达式))

C=$(($A+$B))

这种方式$(())中间的$可以省略:$((A+B))

[root@node01 ~]# a=1
[root@node01 ~]# b=2
[root@node01 ~]# ((a++))
[root@node01 ~]# echo $((a+b))
4

(()) 会触发计算
加上 $ 是取结果

expr 算术表达式  

注意:表达式中各操作数及运算符之间要有空格。而且要使用命令引用

C=`expr $A + $B`

[root@node01 ~]# c=`expr $a + $b`
[root@node01 ~]# echo $c
3

        帮助: help let

let: let arg [arg ...]
    Evaluate arithmetic expressions.
    
    Evaluate each ARG as an arithmetic expression.  Evaluation is done in
    fixed-width integers with no check for overflow, though division by 0
    is trapped and flagged as an error.  The following list of operators is
    grouped into levels of equal-precedence operators.  The levels are listed
    in order of decreasing precedence.
    
    id++, id-- variable post-increment, post-decrement
    ++id, --id variable pre-increment, pre-decrement
    -, + unary minus, plus
    !, ~ logical and bitwise negation
    ** exponentiation
    *, /, % multiplication, division, remainder
    +, - addition, subtraction
    <<, >> left and right bitwise shifts
    <=, >=, <, > comparison
    ==, != equality, inequality
    & bitwise AND
    ^ bitwise XOR
    | bitwise OR
    && logical AND
    || logical OR
    expr ? expr : expr
    conditional operator
    =, *=, /=, %=,
    +=, -=, <<=, >>=,
    &=, ^=, |= assignment
    
    Shell variables are allowed as operands.  The name of the variable
    is replaced by its value (coerced to a fixed-width integer) within
    an expression.  The variable need not have its integer attribute
    turned on to be used in an expression.
    
    Operators are evaluated in order of precedence.  Sub-expressions in
    parentheses are evaluated first and may override the precedence
    rules above.
    
    Exit Status:
    If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise..
最后计算结果是0,let命令返回1,计算结果非0,返回0

条件表达式:

[ expression ]

test expression

[[ expression ]]

    帮助:help test

test: test [expr]
    Evaluate conditional expression.
    
    Exits with a status of 0 (true) or 1 (false) depending on
    the evaluation of EXPR.  Expressions may be unary or binary.  Unary
    expressions are often used to examine the status of a file.  There
    are string operators as well, and numeric comparison operators.
    
    File operators:
    
      -a FILE        True if file exists.
      -b FILE        True if file is block special.
      -c FILE        True if file is character special.
      -d FILE        True if file is a directory.
      -e FILE        True if file exists.
      -f FILE        True if file exists and is a regular file.
      -g FILE        True if file is set-group-id.
      -h FILE        True if file is a symbolic link.
      -L FILE        True if file is a symbolic link.
      -k FILE        True if file has its `sticky' bit set.
      -p FILE        True if file is a named pipe.
      -r FILE        True if file is readable by you.
      -s FILE        True if file exists and is not empty.
      -S FILE        True if file is a socket.
      -t FD          True if FD is opened on a terminal.
      -u FILE        True if the file is set-user-id.
      -w FILE        True if the file is writable by you.
      -x FILE        True if the file is executable by you.
      -O FILE        True if the file is effectively owned by you.
      -G FILE        True if the file is effectively owned by your group.
      -N FILE        True if the file has been modified since it was last read.
    
      FILE1 -nt FILE2  True if file1 is newer than file2 (according to
                       modification date).
    
      FILE1 -ot FILE2  True if file1 is older than file2.
    
      FILE1 -ef FILE2  True if file1 is a hard link to file2.
    
    String operators:
    
      -z STRING      True if string is empty.
    
      -n STRING
         STRING      True if string is not empty.
    
      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.
    
    Other operators:
    
      -o OPTION      True if the shell option OPTION is enabled.
      ! EXPR         True if expr is false.
      EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
      EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.
    
      arg1 OP arg2   Arithmetic tests.  OP is one of -eq, -ne,
                     -lt, -le, -gt, or -ge.
    
    Arithmetic binary operators return true if ARG1 is equal, not-equal,
    less-than, less-than-or-equal, greater-than, or greater-than-or-equal
    than ARG2.
    
    Exit Status:
    Returns success if EXPR evaluates to true; fails if EXPR evaluates to
    false or an invalid argument is given.

[root@node01 ~]# test 3 -gt 2
[root@node01 ~]# echo $?
0
[root@node01 ~]# test 3 -lt 2
[root@node01 ~]# echo $?
1

[root@node01 ~]# [ 3 -gt 2 ]
[root@node01 ~]# echo $?
0
[root@node01 ~]# [ 3 -gt 2 ] && echo "结果为true"
结果为true
[root@node01 ~]# [ -a /etc/profile ] && echo "结果为true"
结果为true    
     [ ] 与 [[ ]] 的区别:

[: [ arg... ]
    Evaluate conditional expression.
    
    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.
[[ ... ]]: [[ expression ]]
    Execute conditional command.
    
    Returns a status of 0 or 1 depending on the evaluation of the conditional
    expression EXPRESSION.  Expressions are composed of the same primaries used
    by the `test' builtin, and may be combined using the following operators:
    
      ( EXPRESSION ) Returns the value of EXPRESSION
      ! EXPRESSION True if EXPRESSION is false; else false
      EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false
      EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false
    
    When the `==' and `!=' operators are used, the string to the right of
    the operator is used as a pattern and pattern matching is performed.
    When the `=~' operator is used, the string to the right of the operator
    is matched as a regular expression.
    
    The && and || operators do not evaluate EXPR2 if EXPR1 is sufficient to
    determine the expression's value.
    
    Exit Status:
    0 or 1 depending on value of EXPRESSION.

        1、当使用"-n"或者"-z"这种方式判断变量是否为空时,或者判断空字符串是否相等时,"[ ]"与"[[  ]]"是有区别的。

        使用"[ ]"时需要在变量的外侧加上双引号,[ ]与test命令的用法完全相同,

        使用"[[  ]]"时则不用。

[root@node01 ~]# no=""
[root@node01 ~]# [ -n "$no" ]
[root@node01 ~]# echo $? 
1
[root@node01 ~]# [ -n $no ] #与预期结果相反
[root@node01 ~]# echo $?
0

[root@node01 ~]# [[ -n "$no" ]]
[root@node01 ~]# echo $?
1
[root@node01 ~]# [[ -n $no ]] #与预期结果相同
[root@node01 ~]# echo $?
1

[root@node01 ~]# [ "" != $no ]
-bash: [: : unary operator expected
[root@node01 ~]# [ "" != "$no" ]
[root@node01 ~]# echo $?
1
[root@node01 ~]# [[ "" != $no ]]
[root@node01 ~]# echo $?
1

        2、当使用逻辑连接符时,"[ ]"与"[[  ]]"是有区别的。

                在使用"[[  ]]"时,可以将"&&"或者"||"直接再括号里面使用,但不能使用"-a"或者"-o"对多个条件进行连接。

[root@node01 ~]# [[ 3 -gt 2 && 7 -lt 9 ]]
[root@node01 ~]# echo $?
0

                在使用"[  ]"时,如果使用"-a"或者"-o"对多个条件进行连接,"-a"或者"-o"必须被包含在"[ ]"之内。

[root@node01 ~]# [ 3 -gt 2 -a 7 -lt 9 ]
[root@node01 ~]# echo $?
0

                在使用"[  ]"时,如果使用"&&"或者"||"对多个条件进行连接,"&&"或者"||"必须在"[ ]"之外。

[root@node01 ~]# [ 3 -gt 2 ] && [ 7 -lt 9 ]
[root@node01 ~]# echo $?
0
        3、在使用符号"=~"去匹配正则表达式时,只能使用"[[  ]]"

[root@node01 ~]# tel=13688888888

[root@node01 ~]# [ $tel =~ ^[0-9]{11}$ ]
-bash: [: =~: binary operator expected

[root@node01 ~]# [[ $tel =~ ^[0-9]{11}$ ]]
[root@node01 ~]# echo $?
0
[root@node01 ~]# [[ $tel =~ ^[0-9]{10}$ ]]
[root@node01 ~]# echo $?
1


if 判断

if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
    Execute commands based on conditional.
    
    The `if COMMANDS' list is executed.  If its exit status is zero, then the
    `then COMMANDS' list is executed.  Otherwise, each `elif COMMANDS' list is
    executed in turn, and if its exit status is zero, the corresponding
    `then COMMANDS' list is executed and the if command completes.  Otherwise,
    the `else COMMANDS' list is executed, if present.  The exit status of the
    entire construct is the exit status of the last command executed, or zero
    if no condition tested true.
    
    Exit Status:
    Returns the status of the last command executed.

[root@node01 ~]# if id jeffrey.deng >& /dev/null; then echo "该用户存在"; else echo "该用户不存在"; fi
该用户存在
[root@node01 ~]# if id ajeffrey.deng >& /dev/null; then echo "该用户存在"; else echo "该用户不存在"; fi
该用户不存在

命令执行成功就执行,既命令返回结果 $? 为0

[root@node01 ~]# if [ 3 -gt 2 ]; then echo true; else echo false; fi
true
[root@node01 ~]# if [ 3 -gt 9 ]; then echo true; else echo false; fi
false



for 循环

for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.
    
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
    
    Exit Status:
    Returns the status of the last command executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Arithmetic for loop.
    
    Equivalent to
    (( EXP1 ))
    while (( EXP2 )); do
    COMMANDS
    (( EXP3 ))
    done
    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is
    omitted, it behaves as if it evaluates to 1.
    
    Exit Status:
    Returns the status of the last command executed.
[root@node01 ~]# for ((i=0;i<5;i++)); do echo $i; done
0
1
2
3
4

[root@node01 ~]# for i in a b c; do echo $i; done
a
b
c
[root@node01 ~]# for i in `seq 5`; do echo $i; done
1
2
3
4
5

[root@node01 ~]# oldIFS=$IFS
[root@node01 ~]# IFS=$'\n'
[root@node01 ~]# for i in `ll` ; do echo $i; done
total 1832
-rw-r--r--  1 root root       3 Jun 28 11:41 8
-rw-------. 1 root root     900 Jul 31  2017 anaconda-ks.cfg
drwxr-xr-x  2 root root    4096 Aug 31  2017 back
-rw-r--r--  1 root root       4 Jun 28 11:38 cat
-rw-r--r--  1 root root      41 Aug  7  2017 devin
drwxr-xr-x  2 root root    4096 Jun 19 00:51 exp
[root@node01 ~]# IFS=$oldIFS

IFS为分隔符,这里修改分隔符为换行符

[root@node01 shell]# cat ./diff.sh 
#!/bin/bash
echo '$*: '$*
echo '$@: '$@

echo '$* for: '
for i in "$*"; do
 echo $i;
done

echo '$@ for: '
for i in "$@"; do
 echo $i;
done

[root@node01 shell]# ./diff.sh a b c d e f
$*: a b c d e f
$@: a b c d e f
$* for: 
a b c d e f
$@ for: 
a
b
c
d
e
f
$* 与 $@ 的区别如上
在脚本里 for 未指定 in list 时,默认为 $@


while 循环

while: while COMMANDS; do COMMANDS; done
    Execute commands as long as a test succeeds.
    
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.
    
    Exit Status:
    Returns the status of the last command executed.

[root@node01 shell]# i=5
[root@node01 shell]# while [ $i -gt 0 ]; do echo $i; ((i--)); done
5
4
3
2
1

多个命令," ; " 号隔开

[root@node01 shell]# mkdir dir
[root@node01 shell]# while ls ./dir; do echo "查看该目录"; rm -fr ./dir; done
查看该目录
ls: cannot access ./dir: No such file or directory

[root@node01 ~]# cat ./data.txt 
#!/bin/bash
num=0
while read line; do
  echo $line; 
  ((num++));
done < $1
echo "文件中的行数:$num"

[root@node01 ~]# ./readLine ./data.txt 
行1
行2
行3
行4
行5
行6
行7
行8
行9
行10
文件中的行数:10


练习

添加用户

    要求:
用户密码同用户名
静默运行脚本
避免捕获用户接口,能够通用
程序自定义输出

#!/bin/bash
if [ $# -eq 2 ]; then
 id $1 >& /dev/null && echo "该用户 $1 已存在" && exit 2
 ! useradd $1 >& /dev/null && echo "用户添加错误" && exit 3
 ! passwd $1 --stdin 0<<<$2 >& /dev/null && echo "设置密码出现错误" && exit 4
 echo "用户 $1 创建成功!"
else
  echo "请输入正确的参数!用户名和密码" && exit 1;
fi

[root@node01 shell]# ./usertool dc
请输入正确的参数!用户名和密码
[root@node01 shell]# ./usertool jeffrey.deng jeffrey
该用户 jeffrey.deng 已存在
[root@node01 shell]# ./usertool dc dc
用户 dc 创建成功!

       常见错误:

useradd $1 >& /dev/null || echo "用户添加错误" && exit 3
     这种写法是错误的,无论useradd执行成功与否,exit都会执行,正确如下:

! useradd $1 >& /dev/null && echo "用户添加错误" && exit 3



查找最大的文件

用户给定路径
输出文件大小最大的文件,排除文件夹
递归子目录
      不精确查找(没有忽略文件夹):
du -ah | sort -t $'\t' -k 1 -hr | sed -n '1,5p'
      脚本精确查找:
#!/bin/bash
[ $# -eq 0 ] && echo "需要输入接路径参数" && exit 1
[ ! -d $1 ] && echo "输入的参数不是一个路径" && exit 2
oldIFS=$IFS
IFS=$'\n'
for line in `du -ah $1 | sort -t $'\t' -k 1 -hr`; do
    fileName=`cut -d $'\t' -f 2 0<<<$line`;
    if [ -f $fileName  ]; then
        fileSize=`cut -d $'\t' -f 1 0<<<$line`;
	echo -e "目录 $1 下的最大文件为:\n${fileName}\t${fileSize}" && exit 0;
    fi;
done
echo "目录 $1 下未找到文件!" && exit 3
IFS=$oldIFS

        测试:

[root@node01 shell]# ./findMaxFile
需要输入接路径参数    

[root@node01 shell]# ./findMaxFile /root
目录 /root 下的最大文件为:
/root/upload/spark-1.6.0-bin-hadoop2.6.tgz	276M

[root@node01 shell]# ./findMaxFile ./emptydir
目录 ./emptydir 下未找到文件!

[root@node01 shell]# ./findMaxFile ./usertool
输入的参数不是一个路径



循环遍历文件每一行:

定义一个计数器num
打印num为文件行数
写出三种方法实现

#!/bin/bash

echo "第一种方法:"
num=0
oldIFS=$IFS
IFS=$'\n'
for line in `cat $1`; do
  echo $line;
  ((num++));
done
echo "文件中的行数:$num"
IFS=$oldIFS

echo  "---------------------"

echo "第二种方法:"
num=0
num=`cat $1 | wc -l`
for ((i=1;i<=num;i++)); do
  echo `head -$i $1 | tail -1`
done
echo "文件中的行数:$num"

echo  "---------------------"

echo "第三种方法:"
num=0
while read line; do
  echo $line; 
  ((num++));
done < $1
echo "文件中的行数:$num"

echo  "---------------------"

echo "第四种方法(错误例子):"
num=0
export num
cat $1 | while read line; do 
  echo $line;
  ((num++));
done < $1
echo "文件中的行数:$num"

    测试:

[root@node01 ~]# ./readLine ./data.txt 
第一种方法:
行1
行2
行3
行4
行5
行6
行7
行8
行9
行10
文件中的行数:10
---------------------
第二种方法:
行1
行2
行3
行4
行5
行6
行7
行8
行9
行10
文件中的行数:10
---------------------
第三种方法:
行1
行2
行3
行4
行5
行6
行7
行8
行9
行10
文件中的行数:10
---------------------
第四种方法(错误例子):
行1
行2
行3
行4
行5
行6
行7
行8
行9
行10
文件中的行数:0 #输出为0,父进程变量不会被子进程修改
     错误分析:

num=0
export num
cat $1 | while read line; do 
  echo $line;
  ((num++));
done < $1
echo "文件中的行数:$num"
因为管道两边是在启动的子进程里运行的,
因为是值传递所以子进程操作的 num 为子进程复制父进程的 num,
所以父进程的 num 不会修改,即使 export 也是没用的

七步扩展

1:花括号  

mkdir  -p sdf/{a,b,c}sdf

2: 波浪线 

cd ~devin

3: 命令替换

 ls -l `echo /`

4: 变量&参数  

5: 算术扩展 

num=$((3+4))

6: word拆分

oldIFS=$IFS
IFS=$'\n'
IFS=$oldIFS

7: 路径

    支持模式匹配

8:引用删除 

echo "hello" #删除引号

9: 重定向 

cut -d ':' -f 1 0<<<"key:value"



相关文章:

         Linux Shell - bash(一):变量、重定向

         Linux Shell

添加新评论