Linux与unix Shell编程
Posted 志善志美8
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux与unix Shell编程相关的知识,希望对你有一定的参考价值。
Unix命令行程序和内建指令
文件系统 |
|
---|
程序 |
|
---|
使用环境 |
|
---|
文字编辑 |
|
---|
Shell 程序 |
|
---|
网络 |
|
---|
搜索 |
|
---|
杂项 |
|
---|
1. 文件权限
$ls -l
- rw-r--r-- 1 dave admin 300 Fed 19 22:05 myfile
文件类型 文件权限 文件属主 文件属主dave 的用户组 文件字节长度 文件更新时间 文件名
- rw-r--r-- 1 dave admin 300 Fed 19 22:05 myfile
1 .文件类型
文件权限位前面的那个字符,我们例子中的横杠就是文件的类型,即普通文件类型。
文件类型有七种,它可以从 ls -l命令所列出的结果的第一位看出:
d 目录。l 符号链接(指向另一个文件)。s 套接字文件。b 块设备文件。c 字符设备文件。p 命名管道文件。
- 普通文件,或者更准确地说,不属于以上几种类型的文件。
2.文件的权限:
文件的权限可分为三类:
1) 文件属主,创建该文件的用户。如 -rw:文件属主权限 这是前面三位
2) 同组用户,拥有该文件的用户组中的任何用户。如 -r-: 同组用户权限 这是中间三位
3) 其他用户,即不属于拥有该文件的用户组的某一用户。如 -r-:其他用户权限 这是最后三位
3.修改权限: chmod
1)符合模式:chmod [who] operator [permission] filename
who的含义是:u文件属主权限。g同组用户权限。o其他用户权限。a所有用户(文件属主、同组用户及其他用户)。
operator的含义:+ 增加权限。-取消权限。= 设定权限。
permission的含义:r读权限。w写权限。x 执行权限。s 文件属主和组set -ID。t 粘性位*。l 给文件加锁,使其他用户无法访问。
chmod u+x myfile //赋予文件属主执行权限
2) 绝对模式: chmod [mode] file
其中mode是一个八进制数:
0400 文件属主可读 0040 同组用户可读 0004 其他用户可读
0200 文件属主可写 0020 同组用户可写 0002 其他用户可写
0100 文件属主可执行 0010 同组用户可执行 0001 其他用户可执行
myfile文件具有这样的权限:
rw- r-- r--
4+2 4 4
把相应权限位所对应的值加在一起,就是644。
4.chown和chgrp
chown命令的一般形式为:
chown -R -h owner file
- R选项意味着对所有子目录下的文件也都进行同样的操作。
- h选项意味着在改变符号链接文件的属主时不影响该链接所指向的目标文件。
如:
$ chown mysql hiscore 把 hiscore文件的属主改为mysql
$ chown -R mysql hiscore 递归地把hiscore(数据库名称)目录下的所有文件属主改成mysql
chgrp命令和chown命令的格式差不多
chgrp sybadmin project
把project文件所属的组由admin变为sybadmin(系统中的另外一个用户组) 。
2. ls、find和xargs
ls使用技巧
以找到当前目录中最大的那个文件:
ls -lSrh
“r”的作用是将大的文件列在后面,而“h”则是给出易于人们阅读的输出(MB或者诸如此类)。你也可以搜寻最大的MP3/MPEG文件:
ls -lSrh *.mp*
你也可以通过下面这条命令搜寻最大的目录:
du -kx | egrep -v "\./.+/" | sort -n
Find命令的一般形式为:
find pathname -options [-print -exec -ok]
让我们来看看该命令的参数:
pathname find命令所查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录。
-options 为命令选项
-print find命令将匹配的文件输出到标准输出。
-exec find命令对匹配的文件执行该参数所给出的 shell命令。相应命令的形式为 ' comm -and' {} \;,注意{ }和\;之间的空格。
-ok 和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的 shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。
1. find命令选项
-name 按照文件名查找文件。
-perm 按照文件权限来查找文件。
-prune 使用这一选项可以使find命令不在当前指定的目录中查找, 如果同时使用了-depth选项,那么-prune选项将被find命令忽略。
-user 按照文件属主来查找文件。
-group 按照文件所属的组来查找文件。
-mtime -n +n 按照文件的更改时间来查找文件,
- n表示文件更改时间距现在n天以内,+ n表示文件更改时间距现在n天以前。
find命令还有- atime和-ctime选项,但它们都和-mtime选项相似,所以我们在这里只介绍- mtime选项。
-nogroup 查找无有效所属组的文件,即该文件所属的组在 /etc/groups中不存在。
-nouser 查找无有效属主的文件,即该文件的属主在 /etc/passwd中不存在。
-newer file1 ! file2 查找更改时间比文件file1新但比文件file2旧的文件。
-type 查找某一类型的文件,诸如:
b - 块设备文件。
d - 目录。
c - 字符设备文件。
p - 管道文件。
l - 符号链接文件。
f - 普通文件。
-size n[c] 查找文件长度为n块的文件,带有c时表示文件长度以字节计。
-depth 在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
-fstype 查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etcfstab中找到,该配置文件中包含了本系统中有关文件系统的信息。
-mount 在查找文件时不跨越文件系统mount点。
-follow 如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。
-cpio 对匹配的文件使用cpio命令,将这些文件备份到磁带设备中。
2. find的例子:
1)匹配$ H O M E目录下的所有文件,下面两种方法都可以使用:
$ find $HOME -print
$ find ~ -print
2) 在当前目录中查找suid置位,文件属主具有读、写、执行权限,并且文件所属组的用户和其他用户具有读和执行的权限的文件,可以用:
$ find . -type f -perm 4755 -print
3 )查找系统中所有文件长度为0的普通文件,并列出它们的完整路径,可以用:
$ find / -type f -size 0 -exec ls -l {} \;
可以按照文件长度来查找文件,这里所指的文件长度既可以用块(block)来计量,也可以用字节来计量。以字节计量文件长度的表达形式为N c;以块计量文件长度只用数字表示即可。
在按照文件长度查找文件时,一般使用这种以字节表示的文件长度,在查看文件系统的大小,因为这时使用块来计量更容易转换。
实例1:在当前目录下查找文件长度大于1 M字节的文件
命令:
find . -size +1000000c -print
实例2:在/home/apache目录下查找文件长度恰好为100字节的文件:
命令:
find /home/apache -size 100c -print
实例3:在当前目录下查找长度超过10块的文件(一块等于512字节)
命令:
find . -size +10 -print
4) 查找/var/logs目录中更改时间在7日以前的普通文件,并删除它们,可以用:
$ find /var/logs -type f -mtime +7 -exec rm {} \;
5) 查找系统中所有属于audit组的文件,可以用:
$find /-name -group audit -print
6) 我们的一个审计系统每天创建一个审计日志文件。日志文件名的最后含有数字,这样我们一眼就可以看出哪个文件是最新的,哪个是最旧的。 admin.log文件编上了序号:
admin.log.001、admin.log.002等等。下面的find命令将删除/logs目录中访问时间在7日以前、含有数字后缀的admin.log文件。该命令只检查三位数字,所以相应日志文件的后缀不要超过999。
$ find /logs -name 'admin.log[0-9][0-9][0-9] '-atime +7 -exec rm {} \;
7) 查找当前文件系统中的所有目录并排序,可以用:
$ find . -type d -print -local -mount |sort
8) 查找系统中所有的rmt磁带设备,可以用:
$ find /dev/rmt -print9)从根目录开始查找所有扩展名为.log的文本文件,并找出包含”ERROR”的行
$ find / -type f -name "*.log" | xargs grep "ERROR"
10、使用find在多个文件中替换掉相同的文本
要替换当前目录以及下层目录里所有文件中的Windows为Linux,你可以这样运行:
find . -name '*.txt' -print | xargs perl -pi -e's/Windows/Linux/ig' *.txt
或者如果你更需要让它只作用于普通文件上
find -type f -name '*.txt' -print0 | xargs --null perl -pi -e 's/Windows/Linux/'
3. 后台执行命令
1. crontab
1). crontab的域
是crontab的格式:
分 时 日 月 星期 要运行的命令
第1列 分钟1~59
第2列 小时1~23(0表示子夜)
第3列 日1~31
第4列 月1~12
第5列 星期0~6(0表示星期天)
第6列 要运行的命令
crontab文件的一个条目是从左边读起的,第一列是分,最后一列是要运行的命令,它位于星期的后面。
用横杠-来表示一个时间范围,例如你希望星期一至星期五运行某个作业,那么可以在星期域使用1-5来表示。
使用逗号“,” ,例如你希望星期一和星期四运行某个作业,只需要使用 1,4来表示。
用星号 *来表示连续的时间段。如果你对某个表示时间的域没有特别的限定,也应该在该域填入 *。
该文件的每一个条目必须含有 5个时间域,而且每个域之间要用空格分隔。该文件中所有的注释行要在行首用#来表示。
例子:
分 时 日 月 星期 要运行的命令
30 21 * * * /apps/bin/cleanup.sh :表示每晚的21:30运行/apps/bin目录下的cleanup.sh。
45 4 1,10,22 * * /apps/bin/backup.sh :表示每月1、10、22日的4:45运行/apps/b i n目录下的backup.sh。
10 1 * * 6,0 /bin/find -name "core" -exec rm {} \; :表示每周六、周日的1 : 1 0运行一个f i n d命令。
0,30 18-23 * * * /apps/bin/dbcheck.sh:表示在每天18:00至23:00之间每隔30分钟运行/apps/bin目录下的dbcheck.sh。
0 23 * * 6 /apps/bin/qtrend.sh :表示每星期六的11:00pm运行/apps/bin目录下的qtrend.sh。
每隔30分钟时运行:
*/30 * * * * /apps/bin/cleanup.sh :
2) 创建和提交crontab文件:
创建一个名为davecron。的文件,加入如下的内容:
#15 minutes between 6pm and 6am
0,15,30,45 18-06 * * * /bin/echo `date` > /dev/console
系统将每隔 15分钟向控制台输出一次当前时间。
如果系统崩溃或挂起,从最后所显示的时间就可以一眼看出系统是什么时间停止工作的。
提交crontab文件,cron命令的参数:
$ crontab davecron
现在该文件已经提交给cron进程,它将每隔1 5分钟运行一次。
同时,新创建文件的一个副本已经被放在/var/spool/cron目录中,文件名就是用户名davecron。
2) 常用参数:
crontab -l //查看当前用户下的cron任务
crontab -e //编辑当前用户的定时任务
crontab -u linuxso -e //编辑用户linuxso的定时任务
crontab -r //删除crontab文件
注意:编辑crontab文件,最好先选择好编辑器,选vim(3):
update-alternatives --config editor
There are 3 choices for the alternative editor (providing /usr/bin/editor).
Selection Path Priority Status
------------------------------------------------------------
0 /bin/nano 40 auto mode
1 /bin/ed -100 manual mode
2 /bin/nano 40 manual mode
3 /usr/bin/vim.tiny 10 manual mode
3) $HOME目录中对crontab文件做一备份:
$crontab -l > $HOME/mycron
4) 恢复丢失的crontab文件:
如果不小心误删了crontab文件,假设你在自己的$HOME目录下还有一个备份,那么可以将其拷贝到/var/spool/cron/<username>,其中<username>是用户名。如果由于权限问题无法完
成拷贝,可以用:
$ crontab <filename>
其中,<filename>是你在$HOME目录中副本的文件名。
我建议你在自己的$HOME目录中保存一个该文件的副本。我就有过类似的经历,有数次误删了crontab 文件(因为r键紧挨在e键的右边…) 。这就是为什么有些系统文档建议不要直接
编辑crontab 文件,而是编辑该文件的一个副本,然后重新提交新的文件。
有些crontab 的变体有些怪异,所以在使用crontab 命令时要格外小心。如果遗漏了任何选
项,crontab 可能会打开一个空文件,或者看起来像是个空文件。这时敲crontab 键退出,不要按
< Ctrl - D >,否则你将丢失crontab 文件。
查看crontab服务状态:service crond status
手动启动crontab服务:service crond start
2. at命令提交命令或者shell脚本
1)at命令使用:
at命令允许用户向cron守护进程提交作业,使其在稍后的时间运行。这里稍后的时间可能是指10min以后,也可能是指几天以后。如果你希望在一个月或更长的时间以后运行,最好还是使用crontab文件。一旦一个作业被提交, at命令将会保留所有当前的环境变量,包括路径,不象crontab,只提供缺省的环境。该作业的所有输出都将以电子邮件的形式发送给用户,除非你对其输出进行了重定向,绝大多数情况下是重定向到某个文件中。和crontab一样,根用户可以通过/etc目录下的at.allow和at.deny文件来控制哪些用户可以使用at命令,哪些用户不行。不过一般来说,对at命令的使用不如对crontab的使用限制那么严格。
at命令的基本形式为:
at [-f script] [-m -l -r] [time] [date]
其中,
-f script 是所要提交的脚本或命令。
-l 列出当前所有等待运行的作业。at q命令具有相同的作用。
-r 清除作业。为了清除某个作业,还要提供相应的作业标识(ID);有些UNIX变体只接受atrm作为清除命令。
-m 作业完成后给用户发邮件。
time at命令的时间格式非常灵活:
1) 可以是H、HH.HH MM、HH : MM或H:M,其中H和M分别是小时和分钟。还可以使用a.m.或p.m.。
2)date日期格式可以是月份数或日期数,而且at命令还能够识别诸如today、tomorrow这样的词。现在就让我们来看看如何提交作业。
2)使用at命令提交命令或脚本
使用at命令提交作业有几种不同的形式,可以通过命令行方式,也可以使用at命令提示符。
一般来说在提交若干行的系统命令时,我使用at命令提示符方式,而在提交s h e l l脚本时,使用命令行方式。
如果你想提交若干行的命令,可以在at命令后面跟上日期/时间并回车。然后就进入了at命令提示符,这时只需逐条输入相应的命令,然后按‘ <CTRL - D>’退出。下面给出一个例子:
root@ubuntu:/home/hadoop/testsh# at 16:10
warning: commands will be executed using /bin/sh
at> find /etc -name "passwd" -print
at> <EOT>
at> job 1 at 2012-10-22 16:10
其中,
<EOT>就是<CTRL - D>。在16:10 系统将执行一个简单的find命令。
你应当已经注意到,我所提交的作业被分配了一个唯一标识job 1。该命令在完成以后会将全部结果以邮件的形式发送给我。
如果希望向at命令提交一个shell脚本,使用其命令行方式即可。在提交脚本时使用- f选项。
$ at 3.00pm tomorrow -f /apps/bin/db_table.sh
warning: commands will be executed using /bin/sh
job 8 at 2012-10-23 15:00
在上面的例子中,一个叫做db_table.sh的脚本将在明天下午3:00运行。
还可以使用echo命令向at命令提交作业:
$ echo find /etc -name "passwd" -print | at now +1 minute
4. shell输入与输出
1 . echo
字符串被重定向到一个名为myfile文件中:
$ echo "The log files have all been done"> myfile
2 . read
可以使用read 语句从键盘或文件的某一行文本中读入信息,并将其赋给一个变量。如果只
指定了一个变量,那么read 将会把所有的输入赋给该变量,直至遇到第一个文件结束符或回
车。
它的一般形式为:
read varible1 varible2 ...
只指定了一个变量,它将被赋予直至回车之前的所有内容:
root@ubuntu:/home/testsh# read name
test1
root@ubuntu:/home/testsh# echo $name
test1
root@ubuntu:/home/testsh#
3 . cat
显示myfile1、myfile2、myfile3这三个文件,可以用:
$ cat myfile1 myfile2 myfile3
4 . 管道
格式:命令1 |命令2
其中|是管道符号。
sed、awk和grep都很适合用管道,特别是在简单的一行命令中。在下面的例子中, who命令的输出通过管道传递给awk命令,以便只显示用户名和所在的终端。
root@ubuntu:/home/testsh# who |awk '{print $1 "\t" $2}'
hgs ptty7
hgs pts/0
root@ubuntu:/home/testsh#
5. tee
它的一般形式为:
tee -a files
其中,- a表示追加到文件末尾。
当执行某些命令或脚本时,如果希望把输出保存下来, tee命令非常方便。
我们使用 who命令,结果输出到屏幕上,同时保存在 who.out文件中:
root@ubuntu:/home/testsh# who | tee who.out
hgs tty7 2011-10-21 23:26 (:0)
hgs pts/0 2011-10-21 23:26 (:0.0)
root@ubuntu:/home/testsh# ls
devcont devcront who.out
root@ubuntu:/home/testsh# cat who.out
hgs tty7 2011-10-21 23:26 (:0)
hgs pts/0 2011-10-21 23:26 (:0.0)
6.重定向
command > filename 把把标准输出重定向到一个新文件中
command >> filename 把把标准输出重定向到一个文件中(追加)
command 1 > fielname 把把标准输出重定向到一个文件中
command > filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中
command 2 > filename 把把标准错误重定向到一个文件中
command 2 >> filename 把把标准输出重定向到一个文件中(追加)
command >> filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中 (追加)
command < filename >filename2 把command命令以filename文件作为标准输入,以 filename 2文件作为标准输出
command < filename 把command命令以filename文件作为标准输入
command << delimiter 把从标准输入中读入,直至遇到delimiter分界符
command <&m 把把文件描述符m作为标准输入
command >&m 把把标准输出重定向到文件描述符m中
command <&- 把关闭标准输入
5. grep功能
grep选项
常用的grep选项有:
-c 只输出匹配行的计数。
-i 不区分大小写(只适用于单字符) 。
-h 查询多文件时不显示文件名。
-l 查询多文件时只输出包含匹配字符的文件名。
-n 显示匹配行及行号。
-s 不显示不存在或无匹配文本的错误信息。
-v 显示不包含匹配文本的所有行。
1)如果要在当前目录下所有.doc文件中查找字符串“sort” ,方法:$ grep "sort"*.doc
2)从文件内容查找匹配指定字符串的行:$ grep "被查找的字符串" 文件名
3)从文件内容查找与正则表达式匹配的行:$ grep –e “正则表达式” 文件名
4)查找时不区分大小写:$ grep –i "被查找的字符串" 文件名
5)查找匹配的行数:$ grep -c "被查找的字符串" 文件名
6)从文件内容查找不匹配指定字符串的行:$ grep –v "被查找的字符串" 文件名
7)递归查找目录/etc/apache2下的文件内容“"\/var\/www”:grep "\/var\/www" -i /etc/apache2 -r
6. awk功能
1. awk简单使用:
awk '{print $0}' grade.txt > wow
2. awk过滤access.log日志
#!/bin/sh
#if test -n "$1"; then
# logfile="/var/log/apache2/access.log"
#else
# logfile=$1
#fi
#读取log文件:文件内容格式:
#10.64.56.51 - - [22/Oct/2012:11:51:51 +0800] "GET /appdata/www/img/empty.gif HTTP/1.1" 304 260 "http://10.64.49.18/appdata/www/index.php?act=left" "codx=10100.12206.12208.12209; csdx=210910; project=card; left_action=Action_MultipleAction; PHPSESSID=p6pp5aumcgvit7ohc25fj5niv5" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (Khtml, like Gecko) Chrome/17.0.963.79 Safari/535.11"
#10.64.56.51 - - [22/Oct/2012:11:51:50 +0800] "GET /appdata/www/index.php?act=mid HTTP/1.1" 200 927 "http://10.64.49.18/appdata/www/index.php" "codx=10100.12206.12208.12209; csdx=210910; project=card; left_action=Action_MultipleAction; PHPSESSID=p6pp5aumcgvit7ohc25fj5niv5" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11"
logfile="/var/log/apache2/access.log"
#项目名称
project=$1
if test -z "{$project}"; then
echo "no project name"
exit;
fi
#项目路径
projectDir="/www/$project/crontab"
#datetime=`date -R|awk '{$5=substr($5,0,2)-1 ; print $2"/"$3"/"$4":"$5}'`
#当前时间格式化成和access.log时间格式一样
datetime=`date -R -d last-hour|awk '{$5=substr($5,0,2); print $2"/"$3"/"$4":"$5}'`
datafile=`pwd`"/log/"`date -d last-hour +%Y-%m-%d_%H`"_$project.log"
flagFile=`pwd`"/log/"`date -d last-hour +%Y-%m-%d_%H`"_$project"
if [ -f $flagFile ];then
echo "flag exist:" $flagFile
exit
fi
projectPath="$project/www/index.php"
#功能:把appache的access.log日志根据项目名和日期,按一定格式,输出到指定文件中
#使用awk解析date=$datetime接受外部变量,substr($5,0,14)==date中的变量date不要带$
#-F 分隔符:[][" ],即使用[][" ]分割每行,没有是使用空格
#project=$projectPath date=$datetime接受外部的变量
#
awk -F '[][" ]' '{hh=substr($5, index($5,":")+1);ydate=substr(date,0, index(date, ":")-1);if(substr($5,0,14)==date&&$10~project)print $1"\t"ydate"\t"hh"\t"$10 }' project=$projectPath date=$datetime $logfile > $datafile
size=`ls -ls $datafile| awk '{print $6}'`
if [ $size == 0 ];then
echo "Empty log"
rm $datafile
exit;
else
echo `pwd`"/log/"`date -d last-hour +%Y-%m-%d_%H` > $flagFile
fi
phpdir="/www/$project/crontab/data/accessLog.php"
if [ ! -f $phpdir ]; then
echo "no php file:"$phpdir
rm $datafile
exit
fi
if [ ! -f $datafile ]; then
echo "no datafile:" $datafile
exit
fi
#php
php $phpdir $datafile
#使用:./cataccess.sh farm
7. 查看文件内容:head,tail,sed
相信最基本的cat、more和less你已经很熟悉了,如果有特殊的要求呢:
1. 如果你只想看文件的前5行,可以使用head命令,如:
head -5 /etc/passwd
2. 如果你想查看文件的后10行,可以使用tail命令,如:
tail -2 /etc/passwd 或 tail -n 2 /etc/passwd
tail -f /var/log/messages
参数-f使tail不停地去读最新的内容,这样有实时监视的效果,用Ctrl+c来终止!
3. 查看文件中间一段,你可以使用sed命令,如:
sed -n '5,10p' /etc/passwd
这样你就可以只查看文件的第5行到第10行。
tail语法格式:
tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]
或者
tail [ -r ] [ -n Number ] [ File ]
使用说明:
tail 命令从指定点开始将 File 参数指定的文件写到标准输出。如果没有指定文件,则会使用标准输入。 Number 变量<br />指定将多少单元写入标准输出。 Number 变量的值可以是正的或负的整数。如果值的前面有 +(加号),从文件开头<br />指定的单元数开始将文件写到标准输出。如果值的前面有 -(减号),则从文件末尾指定的单元数开始将文件写到<br />标准输出。如果值前面没有 +(加号)或 -(减号),那么从文件末尾指定的单元号开始读取文件。
主要参数:
-b Number 从 Number 变量表示的 512 字节块位置开始读取指定文件。
-c Number 从 Number 变量表示的字节位置开始读取指定文件。
-f 如果输入文件是常规文件或如果 File 参数指定 FIFO(先进先出),那么 tail
命令不会在复制了输入文件的最后的指定单元后终止,而是继续从输入文件读取和复
制额外的单元(当这些单元可用时)。如果没有指定 File 参数,并且标准输入是管道
则会忽略 -f 标志。tail -f 命令可用于监视另一个进程正在写入的文件的增长。
-k Number 从 Number 变量表示的 1KB 块位置开始读取指定文件。
-m Number 从 Number 变量表示的多字节字符位置开始读取指定文件。使用该标志提供
在单字节和双字节字符代码集环境中的一致结果。
-n Number 从首行或末行位置来读取指定文件,位置由 Number 变量的符号(+ 或 - 或无)
表示,并通过行号 Number 进行位移。
-r 从文件末尾以逆序方式显示输出。
-r 标志的缺省值是以逆序方式显示整个文件。
如果文件大于 20,480 字节,那么-r标志只显示最后的 20,480 字节。
-r 标志只有与 -n 标志一起时才有效。否则,就会将其忽略
7. sed和awk的常用实例
一、文本间隔
1、在每一行后面增加一空行
sed G guo.sh
awk '{printf("%s\n\n",$0 ) }'
2、将文件中原来的空行删掉,并在在每一行后边增加一空行
sed '/^$/d;G '
awk '!/^$/ {printf("%s\n\n",$0 ) }'
3在匹配式样的行前插入一空行
sed '/good/i\\'
sed '/hello/{x;p;x;}'
awk '{ if(/hello/) printf("\n\%s\n",$0);else print $0}'
4、在匹配式样的行后插入一空行
sed '/good/a\\'
sed '/hello/G'
awk '{if(/hello/) printf("%s\n\n",$0) ;else print $0}'
5、在匹配式样的行前、行后各插入一空行
sed '/hello/{x;p;x;G;}'
awk '{ if(/hello/) printf("\n\%s\n\n",$0);else print $0}'
二、文本的替换
1、在每一行查找到good,然后把good替换为bad
sed 's/good/bad/'只把每行的第一个good替换为bad
sed 's/good/bad/2'只把每行的第二个good替换为bad
sed 's/good/bad/g'把每一行的所有good替换为bad
sed 's/
sed 's/
awk '{sub(/good/,"bad"); print $0}'只把每行的第一个good替换为bad
awk '{gsub(/good/,"bad"); print $0}'把每一行的所有good替换为bad
cat test |tr 'root' 'good'
cat test |tr 'root' 'god'
sed 's/root/good/p' test
awk '{gsub(/root/,"good");print $0}' test
awk '{gsub(/root/,"god");print $0}' test
通过对比可知tr的替换两个字串必须等长度,而sed不能把说有的root替换
2、只在出现字符串fell字符串的前提下,将找到的行中的good替换为bad
sed '/fell/ s/good/bad/g'
awk '{if(/fell/) gsub(/good/,"bad"); print $0 }'
3、只在不出现字符串fell字符串的前提下,将找到的行中的good替换为bad
sed '/fell/ !s/good/bad/g'
awk '{if(!/fell/) gsub(/good/,"bad"); print $0 }'
4、不管是good、fell还是sun,一路替换为bad
sed 's/good/bad/g;s/fell/bad/g;s/sun/bad/g'
sed 's/good\|fell\|sun/bad/g'
awk '{gsub(/good|fell|sun/,"bad") ; print $0}'
5、倒置所有行,第一行变为最后一行(模拟tac)
sed '1!G;h;$!d'
sed -n '1!G;h;$p'
awk '{A[i++]=$0} END{for (j=i-1;j>=0;j--) print A[j]}'
6、将每两行连接为一行
sed '$!N;s/\n/ /'
awk '{f=!f;if(!f) printf("%s",$0);else printf("%s\n",$0)}'
7、在文件中每隔5行显示一空行
sed '0~5G'
sed 'n;n;n;n;G'
awk '{print $0 ;i++;if(i==5) {printf( "\n") ;i=0}}'
三、选择性的显示特定行
1、显示文件的前10行
sed10q
awk '{print ;if(NR==10) exit }'
2、显示文件的第一行
sed q
awk '{ print;exit}'
3、显示文件的倒数第二行
sed -e '$!{h;d;}' -e x当文件只有一行时,输出空行
sed -e '1{$q;}' -e '$!{h;d;}' -e x当文件只有一行时,显示该行
sed -e '1{$d;}' -e '$!{h;d;}' -e x当文件只有一行时,不输出
awk '{ B=A;A=$0} END{ print B}'当文件只有一行时,输出空行
4、只显示匹配正则表达式的行
sed -n '/good/p'
sed '/good/!d'
awk '/good/ {print $0}'
awk '/good/'
grep 'good'
5、只显示不匹配正则表达式的行
sed -n '/good/!p'
sed '/good/d'
awk '!/good/ {print $0}'
grep -v 'good'
6、显示匹配行的上一行,而不显示匹配行
sed -n '/good/{g;1!p;};h'
awk '/good/ {print A} {A=$1}
7、显示匹配行的下一行,而不显示匹配行
sed -n '/good/{n;p;}'
awk '{if(A) print;A=0}/23/{A=1}'
8、显示文本的制定行
sed -n '3,5p'
sed '3,5!d'
awk '{if(NR>=3 &&NR<=5) print } '
目录: 1、不显示文件中的空行 2、删除文件的1到5行3、删除文件注释行4、打印匹配行5、显示从字符1到字符2的中间行6、匹配特别表达式7、替代文本
1、不显示文件中的空行
[guo@guo~]$ grep -v '^$' rc.local
[guo@guo~]$ sed -e '/^$/d' rc.local
[guo@guo~]$ awk '!/^$/{print $0 }' rc.local
2、删除文件的1到5行
[guo@guo~]$ cat test
[guo@guo~]$ sed -e '1,5d' test
[guo@guo~]$ awk '{if(NR>5 ) print $0} ' test
3、删除文件注释行
[guo@guo~]$ sed -e "/^#/d" rc.local
[guo@guo~]$ awk '!/^#/{print $0}' rc.local
[guo@guo~]$ grep -v '^#' rc.local
5、显示从字符1到字符2的中间行
[guo@guo~]$ sed -n -e '/hello/,/sorry/p' test1
[guo@guo~]$ awk '/hello/,/sorry/ {print $0 }' test1
6、匹配特别表达式
[guo@guo~]$ sed -n -e '/main[[:space:]]*(/,/^}/p' for.c
1、通过awk访问系统环境变量
[guo@guoawk]$ awk 'BEGIN { print ENVIRON["HOME"]; printENVIRON["PATH"]}'
/home/guo
/usr/lib/qt-3.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin
2、awk中的算术运算符
[guo@guoawk]$ awk 'BEGIN {print "3+2=" 3+2 }'
3+2=5
[guo@guoawk]$ awk 'BEGIN {print "2^10=" 2^10 }'
2^10=1024
[guo@guoawk]$ awk 'BEGIN {print "(3+1)*4/2=" (3+1)*4/2}'
(3+1)*4/2=8
awk支持的运算符有+ - * / % ^。
4、awk的循环
if语句
[guo@guoawk]$ cat num
12243535
890232
232 9809
890 -8990
[guo@guoawk]$ awk '{if($1>$2) print $0}' num
890232
890 -8990
[guo@guoawk]$ awk '{if($1>$2) {print $0 ; print $1 "is larger than"$2}}' num
890232
890islarger than232
890 -8990
890islarger than-8990
if/else
[guo@guoawk]$ awk '{if($1>$2) print $1 ;else print $2}' num
3535
890
9809
890
[guo@guoawk]$ awk '{if($1>$2) {count++ ;print count} else print $2}' num
3535
1
9809
2
以上是关于Linux与unix Shell编程的主要内容,如果未能解决你的问题,请参考以下文章
linux/unix 的 shell编程里 pipe功能指的是啥功能?