SHELL常用语法详细说明
1.获取从1970-01-01 00:00:00 UTC到现在的秒数(用于计算程序执行的时间)
cur_sec=`date '+%s'`
2.单双引号的区别:
单引号:当shell碰到第一个单引号时,它忽略掉其后直到右引号的所有特殊字符,所以echo '$X'输出的是 $X
双引号:双引号作用与单引号类似,区别在于它没有那么严格。单引号告诉shell忽略所有特殊字符,而双引号只要求忽略大多数,
具体说,括在双引号中的三种特殊字符不被忽略:$,\,`,
即双引号会解释字符串的特别意思,而单引号直接使用字符串.如果使用双引号将字符串赋给变量并反馈它,
实际上与直接反馈变量并无差别。如果要查询包含空 格的字符串,经常会用到双引号
如:echo "$X" 会输出变量X的值,而不是$X
3.echo * 可以输出当前路径下的所有文件名
示例:
x=*;echo $x
shell扫描命令行,把x的值设为星号*;
shell再次扫描命令行,碰到星号*,把它替换成当前目录下的文件清单;
shell启动执行echo命令,把文件清单作为参数传递给echo.
这个赋值的先后次序非常重要:shell先作变量替换,然后作文件名替换,最后把这行处理为参数
4. 反引号(``)
命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置。
shell中有两种方法作命令替换:把shell命令用反引号或者$(...)结构括起来,其中,$(...)格式受到POSIX标准支持,也利于嵌套
反引号和$()的功能是命令替换,将反引号或$()中的字符串做为命令来执行,
我们在用shell编程时经常用的到 将系统命令的执行结果赋给一个变量 但反引号内不能再引用反引号,而$()中可以引用反引号
如 echo date 输出的是date字符串
echo `date` 输出的就是日期字符串 将``内的字符串作为命令执行,然后再echo输出
$()同理
5.反斜杠 backslash-escaped( \ )
反斜杠一般用作转义字符,或称逃脱字符,linux如果echo要让转义字符发生作用,就要使用-e选项,且转义字符要使用双引号
echo -e "\n"
反斜杠的另一种作用,就是当反斜杠用于一行的最后一个字符时,shell把行尾的反斜杠作为续行,这种结构在分几行输入长命令时经常使用
6.给变量赋值时,不要在“=”两边留空格;最好是使用单引号或者双引号
name=xxxx; name="xxxxx" name='xxxxxxxx' 注意单双引号的区别
7.if-else语法:
if condition1
then
statement1
elif condition2
then
statement2
elif condition3
then
statement3
……
else
statementn
fi
(简单说就是只要出现if,不管是if还是elif都算,都必须跟一个then,涉及到有elif的,后续必须跟一个else,然后才能fi)
8.判断文件属性等:
#!/bin/sh
# 判断文件是否存在
myPath="/var/log/httpd/"
myFile="/var /log/httpd/access.log"
# 这里的-x 参数判断$myPath是否存在并且是否具有可执行权限
if [ ! -x "$myPath"]; then
mkdir "$myPath"
fi
# 这里的-d 参数判断$myPath是否存在
if [ ! -d "$myPath"]; then
mkdir "$myPath"
fi
# 这里的-f参数判断$myFile是否存在
if [ ! -f "$myFile" ]; then
touch "$myFile"
fi
# 其他参数还有-n,-n是判断一个变量是否是否有值
if [ ! -n "$myVar" ]; then
echo "$myVar is empty"
exit 0
fi
# 两个变量判断是否相等
if [ "$var1" = "$var2" ]; then
echo '$var1 eq $var2'
else
echo '$var1 not eq $var2'
fi
#shell判断文件夹是否存在
#如果文件夹不存在,创建文件夹
if [ ! -d "/myfolder" ]; then
mkdir /myfolder
fi
#shell判断文件,目录是否存在或者具有权限
folder="/var/www/"
file="/var/www/log"
# -x 参数判断 $folder 是否存在并且是否具有可执行权限
if [ ! -x "$folder"]; then
mkdir "$folder"
fi
# -d 参数判断 $folder 是否存在
if [ ! -d "$folder"]; then
mkdir "$folder"
fi
# -f 参数判断 $file 是否存在
if [ ! -f "$file" ]; then
touch "$file"
fi
# -n 判断一个变量是否有值
if [ ! -n "$var" ]; then
echo "$var is empty"
exit 0
fi
# 判断两个变量是否相等
if [ "$var1" = "$var2" ]; then
echo '$var1 eq $var2'
else
echo '$var1 not eq $var2'
fi
# 判断两个字符串是否相同
if [ "$var1"X = "$var2"X ]
then
echo "相等"
fi
#if - elif - else -fi
if [ "$var"X = "yes"X ]
then
echo "yes"
elif [ "$var"X = "no"X ]
then
echo "no"
else
echo "非法"
fi
#数字判断大小
#-gt是大于
#-lt是小于
#-eq是等于
#-ne是不等于
#-ge是大于等于
#le是小于等于
#且字符数字可以直接用来和数字进行比较大小,不需要进行转化为数字
var=`echo "55"`
if [ $var -eq 55 ]
then
echo "等于55"
else
echo "不等于55"
fi
9.shell中引用函数问题(注意定义要在引用前,且函数名和大括号之间有空格)
#1.函数的定义
function func1 {
}
#2.无参函数调用:函数名
func1
#3.函数的输入参数
function func2 {
#定义变量avr1获取函数第一个参数
var1=$1
#var2获取函数第二个参数
var2=$2
代码处理
}
#4.有参函数调用:函数名 参数
#g_var1和g_var2是外部变量,也可以是固定的值
func2 $g_var1 $g_var2
#5.函数返回值,有两种:
#5.1.通过return 数值;然后使用$?来获取
# 说明:$?是接收上一条函数的执行结果,$?接收函数的执行结果,执行结果其实就是其返回值,就是return 传出来的数值(return只能是数字,不能是字符串之类的),如果函数中没有显式调用return返回出来状态,那么系统会使用函数中最后一条shell指令的执行结果作为返回值,如果函数A最后一条指令调用其他函数B,如:那么A的返回值就是B的返回值。
# 用$?来接收函数的执行状态,但是$?要紧跟在函数调用处的后面
#示例:
#函数定义,需在调用之前
function test {
代码处理
if [ contidion ]
then
return 2
else
return 1
fi
}
#函数调用
test
#函数调用后,立即使用$?来获取返回值,并保存在变量RESULT中
RESULT=$?
echo $RESULT
#5.2.通过标准输出流,输出信息,使用变量和命令替换符``来获取
#用变量接收函数返回值,函数用echo等标准输出将要返回的东西打印出来。
function test {
代码处理
if [ contidion ]
then
echo "2"
else
echo "1"
fi
}
#函数执行结果标准输出的数字存在RESULT中。由于echo是数字字符,作用类似于return
#它几乎就是return和echo不一样,但是有一点一定要注意,不能向标准输出一些不是结果的d数据
#比如调试信息,这些信息可以重定向到一个文件中解决,特别要注意的是,脚本中用到其它类似grep这样的命令的时候,一定要记得1>/dev/null 2>&1来空这些输出信息输出到空设备,避免这些命令的输出,后续17做解释
RESULT=`test`
#5.3 echo + return 同时使用
function test {
#代码处理
echo "hello"
return 100
}
RESULT=`test`
# $?需要在函数执行后,立即获取,中间不能有其他命令执行
VAL=$?
echo "$RESULT"
echo "$VAL"
#运行结果是:
hello
100
10.使用expr 计算时,注意空格
var1=`expr $var1 + 1` (注意加号左右两边的空格)
11.tail命令
tail -n filename (打印filename文件的后n行)
tail -f filename (实时更新文件最后多少行,应该是新出现多少就更新多少)
12.head命令
head -n filename (打印文件前n行)
13. awk命令
echo "xxx,yy,zz,ddd"|awk -F , '{print $1}' (使用逗号作为分隔符,进行字段划分,且打印分隔后的第1个字段)
14.sed命令
#将filename文件中的xx替换为yyy(一行出现多个xx时,只替换第一个)
sed s/xx/yyy filename
#全部替换
sed s/xx/yyy/g filename
#打印filename的第count行
sed -n "$count"p filename
#a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)
sed '2a drink tea' #在第二行后(亦即是加在第三行)加上『drink tea?』字样
15.while循环 实现for循环(递增)
count=1
total=100
while [ count -le $total ]
do
echo $count
count=`expr $count + 1`
#此处引申一下,字符串也可以如此拼接:str=$str"val",将原来str的值加上val作为新的字符串,赋值给str变量
done
#死循环:每10s判断condition是否成立,成立则退出while循环,不成立则sleep 10继续判断
while [ 1 ]
do
if [ condition ]
then
#达到条件退出
break;
else
sleep 10
fi
done
16.shell中的if条件判断 且 或
#且:
# 方法1:
if [ c1 -a c2 ]; then
…
fi
# 方法2:
if [ c1 ] && [ c2 ]; then
…
fi
#或:
# 方法1:
if [ c1 -o c2 ]; then
…
fi
# 方法2:
if [ c1 ] || [ c2 ]; then
…
fi
17.输出重定向到空设备文件1>/dev/null 2>&1
1>/dev/null 2>&1
#命令解释:
#1.标准输入stdin文件描述符为0,标准输出stdout文件描述符为1,标准错误stderr文件描述符为2
#2./dev/null 空设备文件,相当于垃圾桶
#3.重定向符号:>
#故:将stdout标准输出重定向到空设备文件/dev/null ,同时将stderr标准错误输出的重定向跟stdout标准输出重定向一致,也输出到空设备文件/dev/null。
示例:
#抛弃grep的结果
grep "xxxx" filename | 1>/dev/null 2>&1
#丢弃filename的显示内容
cat filename > /dev/null
18.shel常用特殊变量
$# 代表传入参数的个数
$@ 代表传入参数的列表
$0 代表脚本本身
$1 代表传入的第一个参数,$2,$3...以此类推
$* 以字符串方式显示所有传入的参数
$$ 脚本运行的进程ID
$? 显示最后命令的退出状况,0表示没有错误
${#str} 获取str字符变量的长度
echo $((10*10)) 进行算术运算;linux系统下,随时进行计算,不需要打开计算器。
19./dev/null
/dev/null:在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF。
在程序员行话,尤其是Unix行话中,/dev/null 被称为位桶(bit bucket)或者黑洞(black hole)。空设备通常被用于丢弃不需要的输出流,或作为用于输入流的空文件。这些操作通常由重定向完成。
/dev/null 的日常使用:把/dev/null看作"黑洞"。它等价于一个只写文件,并且所有写入它的内容都会永远丢失,而尝试从它那儿读取内容则什么也读不到。然而, /dev/null对命令行和脚本都非常的有用。
我们都知道 cat $filename
会输出filename对应的文件内容(输出到标准输出)
而使用cat $filename >/dev/null
则不会得到任何信息,因为我们将本来该通过标准输出显示的文件信息重定向到了 /dev/null;使用 cat $filename 1>/dev/null
也会得到同样的效果,因为默认重定向的 1 就是标准输出
使用 cat $filename
时如果filename对应的文件不存在,系统肯定会报错: “ cat: filename: 没有那个文件或目录 ” 。
如果我们不想看到错误输出呢?我们可以禁止标准错误: cat $badname 2>/dev/null
有些时候,我并不想看道任何输出,我只想看到这条命令运行是不是正常,那么我们可以同时禁止标准输出和标准错误的输出:
cat $filename >/dev/null 2>&1
#解释:1. >/dev/null 这条命令的作用是将标准输出1重定向到/dev/null中。
2. 2>&1 这条命令用到了重定向绑定,采用&可以将两个输出绑定在一起。这条命令的作用是错误输出将和标准输出同用一个文件描述符,就是错误输出将会和标准输出输出到同一个地方。
linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令,所以>/dev/null 2>&1的作用就是让标准输出重定向到/dev/null中(丢弃标准输出),然后错误输出由于重用了标准输出的描述符,所以错误输出也被定向到了/dev/null中,错误输出同样也被丢弃了。执行了这条命令之后,该条shell命令将不会输出任何信息到控制台,也不会有任何信息输出到文件中。
>/dev/null 2>&1 与 2>&1 >/dev/null的区别
乍眼看这两条命令貌似是等同的,但其实大为不同。
inux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令。那么我们同样从左到右地来分析2>&1 >/dev/null:
2>&1:将错误输出绑定到标准输出上。由于此时的标准输出是默认值,也就是输出到屏幕,所以错误输出会输出到屏幕。
>/dev/null:将标准输出1重定向到/dev/null中。
>
我们用一个表格来更好地说明这两条命令的区别:
命令 | 标准输出 | 错误输出 |
---|---|---|
>/dev/null 2>&1 | 丢弃 | 丢弃 |
2>&1 >/dev/null | 丢弃 | 屏幕 |
>/dev/null 2>&1 与 >/dev/null 2>/dev/null区别
那么可能会有些同学会疑问,为什么要用重定向绑定,而不是像>/dev/null 2>/dev/null这样子重复一遍呢。
为了回答这个问题,我们回到刚才介绍输出重定向的场景。我们尝试将标准输出和错误输出都定向到out文件中:
# ls a.txt b.txt >out 2>out
# cat out
a.txt
�法访问b.txt: 没有那个文件或目录
竟然出现了乱码,这是为啥呢?这是因为采用这种写法,标准输出和错误输出会抢占往out文件的管道,所以可能会导致输出内容的时候出现缺失、覆盖等情况。现在是出现了乱码,有时候也有可能出现只有error信息或者只有正常信息的情况。不管怎么说,采用这种写法,最后的情况是无法预估的。
而且,由于out文件被打开了两次,两个文件描述符会抢占性的往文件中输出内容,所以整体IO效率不如>/dev/null 2>&1来得高。
nohup结合
我们经常使用nohup command &命令形式来启动一些后台程序,比如一些java服务:
nohup java -jar xxxx.jar &
#输出信息会输出到nohup.out文件中
为了不让一些执行信息输出,我们还会加上刚才提到的>/dev/null 2>&1命令来丢弃所有的输出:
nohup java -jar xxxx.jar >/dev/null 2>&1 &
20.uniq与sort -u 两种去重的区别
uniq
所谓的重复是连续出现的相同记录会被去掉
sort -u
是所有记录中,相同的记录都会被去掉
21.grep 命令
Linux grep 命令用于查找文件里符合条件的字符串。
grep 指令用于查找内容包含指定的范本样式的文件,如果发现某文件的内容符合所指定的范本样式,预设 grep 指令会把含有范本样式的那一列显示出来。若不指定任何文件名称,或是所给予的文件名为 -,则 grep 指令会从标准输入设备读取数据。
-a 或 --text : 不要忽略二进制的数据。
-A<显示行数> 或 --after-context=<显示行数> : 除了显示符合范本样式的那一列之外,并显示该行之后的内容。
-b 或 --byte-offset : 在显示符合样式的那一行之前,标示出该行第一个字符的编号。
-B<显示行数> 或 --before-context=<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前的内容。
-c 或 --count : 计算符合样式的列数。
-C<显示行数> 或 --context=<显示行数>或-<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前后的内容。
-d <动作> 或 --directories=<动作> : 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。
-e<范本样式> 或 --regexp=<范本样式> : 指定字符串做为查找文件内容的样式。
-E 或 --extended-regexp : 将样式为延伸的正则表达式来使用。
-f<规则文件> 或 --file=<规则文件> : 指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。
-F 或 --fixed-regexp : 将样式视为固定字符串的列表。
-G 或 --basic-regexp : 将样式视为普通的表示法来使用。
-h 或 --no-filename : 在显示符合样式的那一行之前,不标示该行所属的文件名称。
-H 或 --with-filename : 在显示符合样式的那一行之前,表示该行所属的文件名称。
-i 或 --ignore-case : 忽略字符大小写的差别。
-l 或 --file-with-matches : 列出文件内容符合指定的样式的文件名称。
-L 或 --files-without-match : 列出文件内容不符合指定的样式的文件名称。
-n 或 --line-number : 在显示符合样式的那一行之前,标示出该行的列数编号。
-o 或 --only-matching : 只显示匹配PATTERN 部分。
-q 或 --quiet或--silent : 不显示任何信息。
-r 或 --recursive : 此参数的效果和指定"-d recurse"参数相同。
-s 或 --no-messages : 不显示错误信息。
-v 或 --invert-match : 显示不包含匹配文本的所有行。
-V 或 --version : 显示版本信息。
-w 或 --word-regexp : 只显示全字符合的列。
-x --line-regexp : 只显示全列符合的列。
-y : 此参数的效果和指定"-i"参数相同。
–未完待续–