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语言中相反
0 :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"
相关文章: