Linux学习笔记(四)——Linux_shell脚本基础
一、BashShell脚本初步之前我们学习了很多Linux命令,但是这些命令都是在命令提示符下执行的,一次只能执行一条命令并产生结果。如创建一个文件或目录等等。但是有些情况下,我们需要执行多个命令来完成一个完整的任务,我们可以在命令行提示符下也可以同时执行多个命令,但需要用分号分割每个单独的命令,如下所示,先定位到当前用户的工作目录下,然后在目录下创建一个logs目录,并且在logs目录中创建一个空的syslog.log日志文件并在日志文件中添加当前的系统日期和时间。
命令:
cd/home/yarn ; mkdir logs ; cd logs ; touch syslog.log ; date > logs.log
命令执行后,会在/home/yarn目录下首先创建一个目录logs,然后切换到logs目录下,通过touch命令创建一个空的日志文件syslog.log,然后使用date命令将当前系统日期和时间添加到syslog.log日志文件中。
syslog.log日志内容:
2016年 02月18日 星期四17:49:47 CST
虽然我们在命令行提示符同时执行了多条命令,也完成了我们想要的任务,但是这样的命令集并没有被保存,不能重复使用,另外,如果任务较复杂,这样的方式就不是更好的方式了。
9.1 创建一个Bash Shell脚本
创建一个Bash脚本需要使用文件编辑器,将命令集输入到文本文件中,如下:
命令:
vibashTest.sh
bashTest.sh:
#!/bin/bash
…
在脚本的第一行需要输入#!/bin/bash,作用是指定Shell脚本解释器,如果不显示的指定,也可以执行,但是bash提供的函数不能使用。另外的情况是,用户默认的Shell解释器是bash,但是如果其他用户要执行此脚本,这个用户的默认的Shell解释器不是bash,脚本执行过程中可能会出现异常,所以,要求在脚本的第一行要显示的指定Shell脚本解释器。
在Shell脚本中,#号是用来注释信息的,解释器不会执行#号后面的命令,只把他当中一般的注释信息。注释可以用来说明脚本的使用场景和脚本的使用说明,方便其他用户使用脚本。
下面创建一个简单的脚本,实现的功能和之前的例子相同,创建目录和日志文件。首先要使用文本编辑器创建一个文本文件用来编写脚本命令。
命令:
vibash01.sh
例:bash01.sh:
#!/bin/bash
# 创建的第一个bash脚本
# 此脚本的作用是在用户工作目录下创建一个目录,在目录中创建一个日志文件
# 并且将当前的系统日期和时间输入到文件中
# 切换到工作目录
cd/home/yarn
# 创建logs目录
mkdirlogs
# 切换到logs目录
cd logs
# 创建一个空的日志文件
touchsyslog.log
# 将当前系统日期时间添加到syslog.log日志文件中
date> syslog.log
当第一次执行脚本时,系统会警告命令找不到,通常解决的办法有两种,第一种方法是将脚本所在的目录添加到环境变量PATH中,这样系统在执行脚本时会到PATH所指定的目录下去找,找到后执行。另一种方式是使用绝对路径或在脚本所在目录下使用./的方式执行脚本,如下:
/home/yarn/bash02/bash01.sh
cd/home/yarn/bash02
./bash01.sh
如果在环境变量PATH中指定路径或使用绝对路径执行脚本,系统还会发出警告,说用户没有执行的权限,这是因为创建脚本文件时默认情况下是没有执行权限的,如下:
-rw-rw-r--.1 yarn yarn440 2月1911:51 bash01.sh
这和系统默认设置有关,可以重新设置,后面会做介绍。
看到脚本文件的属主有读写权限而没有执行权限,所以要通过命令chmod为属主设置可执行权限。
命令:
chmodu+x bash01.sh
bash01.sh:
-rwxrw-r--.1 yarn yarn440 2月1911:52 bash01.sh
好了,现在就可以执行脚本了。
9.1.1 echo命令
echo命令是将字符串输出到标准输出,通常使用echo命令输出提示信息或检测结果是否正确。
命令:
echoTest Bash script!
命令执行后会在控制台输出:Test Bash script!。没问题!因为echo命令默认后面跟着的是字符串,但是有些情况下,输出会出现不正确的结果,如下面的情况:
命令:
echoTest 'Bash script'!
控制台输出:
TestBash script!
这不是我们想要的结果,单引号被过滤掉了,所以在使用echo命令时,建议将输出的字符串加上双引号,如下:
命令:
echo"Test 'Bash script'"!
控制台输出:
Test'Bash script'!
这次的输出是我们想要的结果。
另外,echo命令输出后会自动添加一个换行符,下一次输出将在新行输出,如下:
命令:
echo"Test 'Bash script'"! ; echo "Helle bash"
控制台输出:
Test'Bash script'!
Hellebash
有时候我们需要将输出同一行显示,这就需要使用-n参数,如下:
命令:
echo -n"Test 'Bash script'"! ; echo "Helle bash"
控制台输出:
Test'Bash script'!Helle bash
9.2 在Bash脚本中使用变量
与Java或其他语言相似,在Bash脚本中也可以使用变量,将值保存到变量中在脚本中使用,下面通过例子说明在Bash脚本中变量的使用。在之前我们讲了Linux系统中的环境变量,那么对Bash脚本的变量就更容易理解了。
9.2.1 Bash脚本中的环境变量
在Linux系统中维护着一组环境变量,用来记录系统的各类信息,如当前的用户、用户ID和主机名称等等信息,这些环境变量的值可以在Bash脚本中使用。可以通过set命令看到Linux系统维护的环境变量的值。
命令:
set
控制台输出:
BASH=/bin/bash
HADOOP_HOME=/usr/local/hadoop
HISTCONTROL=ignoredups
HISTFILE=/home/yarn/.bash_history
HOME=/home/yarn
HOSTNAME=YARN
HOSTTYPE=i386
IFS=$'\t\n'
JAVA_HOME=/usr/local/jdk1.8.0_51
JRE_HOME=/usr/local/jdk1.8.0_51/jre
LANG=zh_CN.utf8
LOGNAME=yarn
OLDPWD=/home/yarn
PATH=/usr/local/jdk1.8.0_51/bin:/usr/local/jdk1.8.0_51/jre/bin:/usr/lib/qt-3.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/yarn/bash01:/usr/local/hadoop/sbin:/usr/local/hadoop/bin:/home/yarn/bin:/home/yarn/bash01
PIPESTATUS=(="0")
PPID=3054
PWD=/home/yarn/bash02
UID=500
USER=yarn
USERNAME=yarn
…
这些环境变量是系统维护的,我们可以在脚本中使用,引用变量需要使用$符号,如下:
例:在脚本中访问系统环境变量
#!/bin/bash
# 使用系统维护的环境变量
echo "当前的用户:$USER"
echo "当前用户ID:$UID"
echo "用户的工作目录:$HOME"
echo "主机名:$HOSTNAME"
echo "系统默认脚本解释器:$BASH"
控制台输出:
当前的用户:yarn
当前用户ID:500
用户的工作目录:/home/yarn
主机名:YARN
系统默认脚本解释器:/bin/bash
这里需要注意的是$符,系统会认为后面跟着的是一般变量,在脚本执行过程中,系统会将变量的值替换显示。所以如果想显示$符到控制台,需要进行转义:
echo "\$USER:$USER"
$USER:yarn
对变量的引用可以可以采用${varname}的方式,大括号中是变量名称,修改上面的例子。
例:采用${varname}的方式访问系统环境变量
#!/bin/bash
# 使用系统维护的环境变量
echo "当前的用户:${USER}"
echo "当前用户ID:${UID}"
echo "用户的工作目录:${HOME}"
echo "主机名:${HOSTNAME}"
echo "系统默认脚本解释器:${BASH}"
控制台输出:
当前的用户:yarn
当前用户ID:500
用户的工作目录:/home/yarn
主机名:YARN
系统默认脚本解释器:/bin/bash
使用效果是相同的,建议使用第二种方式。
9.2.2 Bash脚本中的用户变量
在用户脚本中可以定义和使用变量,定义后的变量可以在脚本中引用。这些变量的生命周期同脚本的执行周期相同,脚本执行结束变量同时在内存中被销毁。为了区别环境变量,用户变量建议使用小写字母,并且变量Var和var是不同的两个变量,要注意变量名区分大小写。
为变量赋值要使用等号,与其他语言的区别是,变量名、等号和变量值之间是不能存在空格。如下:
例:
#!/bin/bash
name=张三
age=22
address=山西太原
echo "name:$name"
echo "age:$age"
echo "address:$address"
Bash脚本中的变量类型会根据变量的值决定,引用变量需要用到$符。
例子:编写两个脚本文件,在第一个脚本中调用第二个脚本,父脚本中设置局部变量,在子脚本中进行访问,因为执行子脚本会启动一个新的子进程,所以父脚本中的局部变量不能访问到。
#!/bin/bash
#这是一个测试局部变量的脚本
name=张三
id=1001
echo"name:$name"
echo"id:$id"
echo"bash02.sh进程号:$$"
#./bash02_1.sh
#bashbash02_1.sh
#../bash02_1.sh
source./bash02_1.sh
例子:编写两个脚本文件,在第一个脚本中调用第二个脚本,父脚本中设置环境变量并使用export命令将用户环境变量导出,在子脚本中进行访问父脚本导出的环境变量,因为执行子脚本会启动一个新的子进程,在子进程中可以访问到父脚本中的导出的用户环境变量。
#!/bin/bash
#测试用户环境变量
exportname=zhangsan
id=1001
exportid
echo"name:$name"
echo"id:$id"
echo"bash03.sh父进程号:$PPID"
echo"bash03.sh进程号:$$"
bash/home/yarn/b2/bash03_1.sh
echo"name:$name"
echo"id:$id"
例子:编写两个脚本文件,在第一个脚本中使用”.”的方式调用第二个脚本,父脚本中设置局部变量,再设置用户环境变量并使用export命令将用户环境变量导出,在子脚本中进行访问父脚本导出的环境变量和局部变量,因为采用.的方式启动子脚本不会启动一个新的子进程,还是在父进程中运行,所以,在子进程中可以访问到父脚本中的导出的用户环境变量和局部变量。
#!/bin/bash
#这是一个测试局部变量的脚本
name=张三
id=1001
echo"name:$name"
echo"id:$id"
echo"bash02.sh进程号:$$"
#./bash02_1.sh
#bashbash02_1.sh
#../bash02_1.sh
source./bash02_1.sh
9.3 exec命令
当使用exec命令执行一个命令或启动一个脚本文件时,会启动一个子进程,但进程ID号还会使用父进程的进程ID号,对于父进程的局部变量exec命令启动的脚本进程是不可见的,而父进程导出的环境变量还可以引用到。当exec命令启动的脚本进程执行结束后,不会返回到父进程,而是将父进程终止。也可以理解为exec启动的脚本进程替代了当前的父进程,并继承了父进程的环境变量,当脚本执行结束后启动脚本进程的当前环境都将会被清除。
语法格式为:
exec 命令
通常情况下命令是一个脚本文件。当这个脚本结束时,相应的进程就结束了。
例子:通常情况下,一个命令或脚本进程结束后,会回到启动命令或脚本进程的父进程,下面例子说明。
#!/bin/bash
#测试exec命令启动脚本
user=zhangsan
export country="中国"
echo "bash04.sh进程号:$$"
exec ./bash04_1.sh
echo "是否执行到这里"
例子:通过exec命令启动的命令或脚本进程执行结束后,不会回到启动脚本的父进程,而是会终止启动脚本的父进程,因为使用的进程ID还是父进程的进程ID,感觉上是没有启动新的进程,还在父进程中执行脚本,但是,实际上还是启动了新的子进程(对父进程的环境复制),只是进程ID(PID)还使用父进程的,当脚本执行结束,父进程也不存在了,不存在返回父进程。
9.3.1 exec命令执行Java程序
使用exec命令执行Java程序,命令格式如下:
execjava> execjava -jar jarname
使用exec命令执行Java程序,当程序执行结束后,执行exec命令的父进程也同样会结束。
例子:
9.3.2 exec命令指定文件描述符
exec命令指定文件描述符在后面的内容中会详细说明。
例子:重定向输出
#!/bin/bash
#测试exec命令重定向输出
echo"chongdingxiangqian"
exec> log.txt
echo"Hello zhangsan"
catbash03.sh
ls
9.4 脚本中的反引号
反引号用于执行命令并且有输出的情况,如:ls,显示目录下的文件信息。并且将输出赋给一个变量。需要注意的是系统会将反引号中的内容作为一个命令并执行。
反引号可以将命令的标准输出值赋值给一个变量,如下:
#!/bin/bash
var=`ls-a`
echo "var:$var"
控制台输出:
var: .
..
.abrt
bash01
.bash_history
.bash_logout
.bash_profile
.bashrc
.cache
.config
.dbus
.dmrc
.esd_auth
…
下面通过一个例子说明反引号的使用方式。如系统服务每天要创建一个日志文件,每个日志文件名要带有日期。
例:使用反引号返回日期字符串
#!/bin/bash
# 将日期格式化输出结果赋值给变量
datestr=`date +%y%m%d`
# 切换到保存日志的目录
cd /home/yarn/bash01
# 将日志的名称保存到一个变量中
logfile=log_${USER}_${datestr}.log
# 创建一个空的日志文件
touch $logfile
# 将当天的日期输入到文件的第一行
date > $logfile
生成的文件:
log_yarn_160226.log
log160226.log日志内容:
2016年 02月26日 星期五17:29:43 CST
9.5 获取命令输出结果的另一种方式
像反引号一样,还可以使用另一种方式获取命令的输出结果。命令格式如下:
var=$(命令)
例子:可以用下面的方法读取命令序列的输出,与返引号相似。
filelist=$(ls| cat -n)
echo $filelist
# 文件列表加行号
filelist=`ls| cat -n`
echo $filelist
# 计算两个整数的和并返回结果
result1=`expr 3 + 4`
result2=$(expr 5 + 5)
echo $result1
echo $result2
# 创建临时文件,并返回文件名称
tmpfile1=`mktemp`
tmpfile2=$(mktemp)
echo $tmpfile1
echo $tmpfile2
# 创建临时目录并返回目录名称
tmpdir1=`mktemp -d`
tmpdir2=$(mktemp -d)
echo $tmpdir1
echo $tmpdir2
9.6 重定向输入和输出
重定向是根据不同需求将标准输出到控制台的信息输出到其他的媒介,如将输出到控制台的警告信息重定向输出到日志文件便于查询。或将从标准输入设备键盘读取数据重定向成从文件中读取数据。
9.6.1 输出重定向
输出重定向常用的方式是将输出到控制台的信息重定向输出到文件中。输出重定向符是大于号 >,命令格式如下:
命令 > filename
只要是有输出信息的命令都可以使用输出重定向符。
ls -a> filename
date> filename
echo "loginUSER:$USER" > filename
输出重定向符是大于号,需要注意的是,如果重定向输出的文件不存在,系统会首先创建文件然后将信息输入到文件中,如果文件存在,则直接将信息输入到文件中。通过输出重定向符每次输出的信息都会将文件中已经存在的信息覆盖,所以如果想向文件中追加信息而不覆盖已存在的信息,需要使用重定向符(>>),下面通过例子说明。
例:将脚本执行过程中的信息重定向输出到日志文件。
#!/bin/bash
# 输出重定向
# 日期格式化到变量
datestr=`date+%y%m%d`
# 日志文件命令
filename=/home/yarn/bash01/log_${USER}_${datestr}.log
# 将当天日期重定向输出到日志文件
date> $filename
# 脚本执行信息追加到日志文件
echo "bashscript begin!" >> $filename
# 切换到工作目录
cd/home/yarn/bash01
# 将信息追加到日志文件
echo"select /home/yarn/bash01" >> $filename
# 创建工作目录
mkdirmapreduce01
# 将信息追加到日志文件
echo"create log dir:/home/yarn/bash01/mapreduce01" >> $filename
# 切换工作目录
cdmapreduce01
# 将信息追加到日志文件
echo"select /home/yarn/bash01/mapreduce01" >> $filename
# 拷贝文件到当前目录
cp/home/yarn/bash01/bash04.sh .
# 将信息追加到日志文件
echo"copy /home/yarn/bash01/bash04.sh to /home/yarn/bash01/mapreduce01">> $filename
# 将脚本执行结束信息追加到日志文件
echo"bash script end!" >> $filename
可以通过:>输出定向符清除文件内容,命令格式如下:
:> filename
:>会把文件filename截断为0长度,就是清除文件内容。如果文件不存在, 那么就创建一个空的文件。:>是一个占位符和定向符组成。
例:将输出信息重定向到文件后,将文件信息清除。
#!/bin/bash
# :>
# 定义变量,文件hello.txt不存在
FILE_DIR=/home/yarn/bash01/dir1/hello.txt
# 将标准输出到文件中
# 将"Hello Hadoop!.Hello Bash!"写到/home/yarn/bash01/dir1/hello.txt中
# 不会在控制台输出,输出重定向到文件中了
echo"Hello Hadoop!.Hello Bash!" > "$FILE_DIR"
# 显示文件/home/yarn/bash01/dir1/hello.txt内容:"Hello Hadoop!.Hello Bash!"
cat"$FILE_DIR"
# 清空/home/yarn/bash01/dir1/hello.txt文件的内容
:>"$FILE_DIR"
# 显示文件内容,为空
cat"$FILE_DIR"
exit 0
例:将输出信息重定向到文件,比较>与>>。
#!/bin/bash
# >>>
# 定义变量
FILE_DIR=/home/yarn/bash01/dir1
# 将"Hello YARN!"写入文件yarn1.txt
echo"Hello YARN!" > "$FILE_DIR"/yarn1.txt
# 显示文件内容:"Hello YARN!"
cat"$FILE_DIR"/yarn1.txt
# 将"Hello MapReduce!"写入文件并覆盖原内容"Hello YARN!"
echo"Hello MapReduce!" > "$FILE_DIR"/yarn1.txt
# 显示文件内容:"Hello MapReduce!"
cat"$FILE_DIR"/yarn1.txt
# 向文件中写入内容:"Hello YARN!"
echo"Hello YARN!" > "$FILE_DIR"/yarn2.txt
cat"$FILE_DIR"/yarn2.txt
# 向文件中追加内容:"Hello MapReduce!",在文件尾部添加,不覆盖原内容
echo"Hello MapReduce!" >> "$FILE_DIR"/yarn2.txt
# 显示内容:
# HelloYARN!
# HelloMapReduce!
cat"$FILE_DIR"/yarn2.txt
exit 0
9.6.2 输入重定向
输入标准设备是键盘,输入重定向是将从标准输入设备读取数据重定向到其他媒介,通常情况下,最常见的是重定向输入到文件,从文件中读取数据到命令,和输出重定向正好相反。命令格式如下:
命令 < filename
为了测试方便,创建一个文本文件file.txt,文件内容如下:
abc
efg
hellojava
shellscript
linux
hadoop
100 ok
50 aaa
355 399
25 2219
99 1000345 33
例子:使用输入重定向符/dev/null
# 切换到目录
cd/home/yarn
# 拷贝不存在的文件
cp file1 file2
执行脚本:
$ t.sh || "文件拷贝失败"
-bash: 文件拷贝失败: command not found
9.10.3 使用()和{}执行命令序列
如果想执行一组命令,可以采用两种方式,将命令组放在()或{}中,如果在一行需要使用命令分隔符;将命令分开,如果不在一行,就不需要了。这两种方式的区别是,()可以在命令行上使用,而{}方式只能在脚本中使用。另外,()方式执行脚本不会改变当前命令行状态。
例子:在命令行执行()语句块
$ (cd /home/yarn;pwd)
/home/yarn
$
另外,这两种方式的区别是,()方式可以引用父脚本中的变量,但不能改变变量的值,而{}方式可以引用父脚本中的变量,也可以改变变量的值。
例子:两种方式引用父进程中的局部变量,并修改变量的值,比较两种方式的区别。
#!/bin/bash
#测试()和{}
name=zhangsan
(
echo $name
name=lisi
echo $name
echo "()中的进程号: $$"
)
echo $name
echo "bash03.sh进程号:$$"
#!/bin/bash
name=zhangsan
{
echo $name
name=lisi
echo $name
echo "{}进程号:$$"
}
echo $name
echo "bash04.sh进程号:$$"
需要注意的是,这两种方式不会启动一个新的子进程,在子进程中执行命令,而是都在父进程中执行。
例子:在脚本中使用两种方式执行,验证是否创建了新的子进程。
另外,在()内声明的变量,在脚本中无法访问,相当于局部变量,而在{}内声明的变量在脚本中可以访问
例子:在()中声明的变量类似局部变量,脚本中不能访问。在{}中声明的变量,脚本中可以访问。
这两种方式通常使用的场景是重定向输入和重定向输出,从一个文件中读取或重定向输出到文件。
例子:使用两种方式重定向输入和重定向输出到文件。
#!/bin/bash
echo "脚本开始执行"
(
cd /home/yarn/b3
echo "切换到/home/yarn/b3目录下"
mkdir d6
echo "创建目录d6"
cd d6
echo "切换到d6下"
touch log.log
echo "创建日志文件log.log"
)>f2
将代码块{…}中的所有标准输出内容都重新定向到文件中,注意,只有标准输出到控制台的内容才会写入到文件中。
例:代码块的用法。
#!/bin/bash
#{}>file
FILE_DIR=/home/yarn/bash01/dir1
# 代码块
{
# 判断变量是否是目录
if [ -d "$FILE_DIR" ]
then
# 标准输出到控制台的信息,所以会写到文件中
echo "Add content to the'$FILE_DIR/yarn3.txt'"
# 标准输出已经重定向到文件中了,所以不会显示到控制台,也不会写到文件中
echo "Bash Sheel!" >>"$FILE_DIR"/yarn3.txt
# 同上
echo "Linux!" >>"$FILE_DIR"/yarn3.txt
fi
# 重新定向到文件中,可以作为日志
} >"$FILE_DIR"/bashbak1
# 显示文件内容:Add content to the'/home/yarn/bash01/dir1/yarn3.txt'
cat"$FILE_DIR"/bashbak1
从文件中输出内容。
例:read命令的用法例子。
#!/bin/bash
# <
FILE_DIR=/home/yarn/bash01/dir1/yarn2.txt
# 从文件中读取第一行到变量line1
read line1< "$FILE_DIR"
# 还是读取第一行
readline2 < "$FILE_DIR"
# 两个变量的内容都是文件的第一行内容:Hello YARN!
echo"$line1"
echo"$line2"
# 代码块{…}中读取两次到两个变量,变量line3读取的是第一行
# 变量line4读取的是文件的第二行
{
read line3
read line4
} <"$FILE_DIR"
echo
# 输出:Hello YARN!
echo"$line3"
# 输出:Hello MapReduce!
echo"$line4"
9.11 grep命令
grep命令使用广泛,允许对文本文件中的内容进行模式查找。如果找到匹配模式的信息会输出到控制台,打印符合条件的所有行。创建测试文件flowlist.txt。
flowlist.txt文件:
1501010001 71.05 2141618 3 07/11/1521:46:57 1006 User001 109 4 303
1501010002 865.86 1686831 2 05/11/1503:52:44 1009 User009 109 1 302
1501010003 652.61 2587675 2 07/14/1519:17:39 1010 User003 110 1 305
1501010004 905.24 1282788 1 04/17/1517:14:09 1010 User004 102 3 304
1501010005 444.25 1624680 1 04/05/1511:40:51 1005 User009 108 1 308
1501010006 48.21 2473714 3 01/18/1523:45:51 1001 User003 110 2 302
1501010007 396.26 2512994 4 08/07/1505:55:16 1005 User009 102 2 308
1501010008 690.74 1259159 2 08/06/1502:48:20 1004 User001 104 4 304
1501010009 122.37 2462139 1 04/27/1508:19:22 1008 User008 105 2 310
grep命令格式:
grep [参数] 查找的内容 [文件]
例子:查找所有以txt结尾的文件中存在字符串的记录并显示到控制台。
$ grep "User009" *.txt
1501010002 865.86 1686831 2 05/11/1503:52:44 1009 User009109 1302
1501010005 444.25 1624680 1 04/05/1511:40:51 1005 User009108 1308
1501010007 396.26 2512994 4 08/07/1505:55:16 1005 User009102 2308
例子:查找存在字符串的行数。
$ grep -c "1005" flowlist.txt
2
例子:查找存在字符串的记录及行号。
$ grep -n "1005" flowlist.txt
5:1501010005 444.251624680 1 04/05/15 11:40:51 1005 User009 108 1308
7:1501010007 396.262512994 4 08/07/15 05:55:16 1005 User009 102 2308
例子:显示不包含条件的记录。
$ grep -v "1005" flowlist.txt
1501010001 71.05 2141618 3 07/11/1521:46:57 1006 User001 109 4303
1501010002 865.86 1686831 2 05/11/1503:52:44 1009 User009 109 1302
1501010003 652.61 2587675 2 07/14/1519:17:39 1010 User003 110 1305
1501010004 905.24 1282788 1 04/17/1517:14:09 1010 User004 102 3304
1501010006 48.21 2473714 3 01/18/1523:45:51 1001 User003 110 2302
1501010008 690.74 1259159 2 08/06/1502:48:20 1004 User001 104 4304
1501010009 122.37 2462139 1 04/27/1508:19:22 1008 User008 105 2310
例子:精确查找符合条件的记录。
$grep "303" flowlist.txt
1501010001 71.05 2141618 3 07/11/1521:46:57 1006 User001 109 4 303
例子:忽略大小写查询。
$ grep -i "user001" flowlist.txt
1501010001 71.05 2141618 3 07/11/1521:46:57 1006 User001109 4303
1501010008 690.74 1259159 2 08/06/1502:48:20 1004 User001104 4304
例子:将查询结果通过管道继续查询符合条件的记录。
$ grep "User001" flowlist.txt | grep "304"
1501010008 690.74 1259159 2 08/06/1502:48:20 1004 User001104 4304
例子:将查询结果输出到文件。
$ grep "304" flowlist.txt > file_304.txt
$ cat file_304.txt
1501010004 905.24 1282788 1 04/17/1517:14:09 1010 User004 102 3304
1501010008 690.74 1259159 2 08/06/1502:48:20 1004 User001 104 4304
例子:查询用户信息。
$grep "yarn" /etc/passwd
yarn:x:500:500:yarn:/home/yarn:/bin/bash
$ grep yarn /etc/passwd
yarn:x:500:500:yarn:/home/yarn:/bin/bash
例子:grep命令不仅可以在文件查找符合条件的行,也可在字符串中查找符合条件的子串。
$ echo "Hello Linux" | grep in
HelloLinux
$echo "I Study Hadoop" | grep "doo"
IStudy Hadoop
9.12 变量设置模式
9.12.1 检查变量是否已经设置值
测试变量是否已设置值或被初始化。如果变量未被初始化,则返回value。
命令格式如下:
var=${var:-value}
var=${var-value}
例子:测试变量是否被初始化,如果未被初始化,在返回一个默认的值。
# 变量name未设初值则返回默认值
$echo ${name:-zhangsan}
zhangsan
# 可以看出,虽然返回了默认值,但是变量name并未赋值
$ echo ${name:-lisi}
lisi
# 为变量name赋值
$ name=wangwu
# 因为变量name已经赋值,所以返回变量的值
$echo ${name:-zhangsan}
wangwu
# 清除变量name
$unset name
# 变量那么未赋初值,返回默认值
$ echo ${name:-zhangsan}
zhangsan
测试变量是否已设置值或被初始化。如果变量未被初始化,则使用另一个设定的值。与上面命令不同之处在于,将默认值赋值给变量。
命令格式如下:
var=${var:=value}
例子:测试变量是否被初始化,如果未被初始化,在返回一个默认的值并将默认值赋值给变量。
# 变量id未被赋值,返回默认值并且将值赋给变量id
$echo ${id:=1001}
1001
# 因为变量id已经赋值1001,所以直接返回
$ echo ${id:=1002}
1001
# 清除变量id
$ unset>
# 变量id未赋值,返回默认值1002并赋值给变量id
$ echo ${id:=1002}
1002
# 显示变量id的值,
$ echo $id
1002
# 因为变量id已经赋值,所以直接返回已有的值
$ echo ${id:=1003}
1002
测试变量是否已设置值或被初始化。如果变量未被初始化,则返回一个空串。如果已设置初始值,则将新值返回但并不赋值给变量。
命令格式如下:
var=${var:+value}
例子:测试变量是否被初始化,如果未被初始化,在返回一个空串。否则,返回新值但不会将新值赋值给变量。
# 变量price未被赋初值,返回空串
$ echo ${price:+100}
# 如果变量price未赋值,将新值200赋值给变量price
$ price=${price:-200}
# 打印变量的值,为200
$ echo $price
200
# 如果变量已经赋值,则返回新值,但是并不会将新值赋给变量price
$ echo ${price:+100}
100
# 打印变量price,变量的值还是旧值200
$ echo $price
200
9.12.2 设置只读变量
在声明变量并赋值后,使用readonly命令修饰,变量就成了只读变量,在整个生命周期内不能修改了。
例子:将变量声明为只读变量。
# 声明变量并赋值
$ name=zhangsan
# 将变量设置成只读变量
$readonly name
# 打印变量的值
$echo $name
zhangsan
# 为变量重新赋值,提示为只读不能修改
$ name=lisi
-bash: name:readonly variable
# 变量声明时设置为只读
$ readonly>
$ echo $id
1001
# 为变量重新赋值,提示为只读变量
$ id=1002
-bash:>
页:
[1]