(这些每每是常常用到,可是各类网络上的材料都语焉不详的东西,我的认为比较有用)html
d 目录 l 符号连接python
s 套接字文件 b 块设备文件linux
c 字符设备文件 p 命名管道文件git
- 普通文件正则表达式
从一个文件或命令输出中抽取或过滤文本时。可以使用正则表达式(RE),正则表达式是一些特殊或不很特殊的字符串模式的集合。shell
基本的元字符集:数据库
^ 只匹配行首。编程
$ 只匹配行尾。数组
* 一个单字符后紧跟*,匹配0个或多个此单字符。安全
[] 匹配[]内字符,能够是一个单字符,也能够是字符序列。能够使
用-来表示[]内范围,如[1-5]等价于[1,2,3,4,5]。
\ 屏蔽一个元字符的特殊含义,如\$表示字符$,而不表示匹配行
尾。
. 匹配任意单字符。
pattern\{n\} 匹配pattern出现的次数n
pattern\{n,\}m匹配pattern出现的次数,但表示次数最少为n
pattern\{n,m\} 匹配pattern出现的次数在n与m之间(n,m为0-255)
几个常见的例子:
显示可执行的文件:ls –l | grep …x...x..x
只显示文件夹:ls –l | grep ^d
匹配全部的空行:^$
匹配全部的单词:[A-Z a-z]*
匹配任一非字母型字符:[^A-Z a-z]
包含八个字符的行:^……..$(8个.)
如下是可用字符类的至关完整的列表:
[:alnum:] 字母数字 [a-z A-Z 0-9]
[:alpha:] 字母 [a-z A-Z]
[:blank:] 空格或制表键
[:cntrl:] 任何控制字符
[:digit:] 数字 [0-9]
[:graph:] 任何可视字符(无空格)
[:lower:] 小写 [a-z]
[:print:] 非控制字符
[:punct:] 标点字符
[:space:] 空格
[:upper:] 大写 [A-Z]
[:xdigit:] 十六进制数字 [0-9 a-f A-F]
尽量使用字符类是颇有利的,由于它们能够更好地适应非英语 locale(包括某些必需的重音字符等等).
shell共有四种引用类型:
“ ” 双引号
‘ ’ 单引号
` ` 反引号
\ 反斜线
l “ ” 可引用除$、` 、\ 、外的任意字符或字符串,“ ”中的变量可以正常显示变量值。
l ‘ ’与“ ”相似,不一样在于shell会忽略任何的引用值。
例如: GIRL=‘girl’
echo “The ‘$GIRL’ did well”
则打印:The ‘girl’ did well
l ` `用于设置系统命令的输出到变量,shell会将` `中的内容做为一个系统命令并执行质。
例如:echo `date` 则打印当前的系统时间。
l \ 用来屏蔽特殊含义的字符:& * + ^ $ ` “ | ?
例如:expr 12 \* 12 将输出144
valiable_name=value 设置实际值到 variable_name中
valiable_name+value 若是设置了variable_name,则重设其值
valiable_name:?value 若是未设置variable_name,则先显示未定义用户错误信息
valiable_name?value 若是未设置variable_name,则显示系统错误信息
valiable_name:=value 若是未设置variable_name,则设置其值
valiable_name-value 同上,但取值并不设置到variable_name
test命令用于测试字符串、文件状态和数字,expr测试和执行数值输出。
Test格式:test condition 或 [ condition ](须要特别注意的是condition的两边都要有一个空格,不然会报错),test命令返回0表示成功。
l 下面将分别描述test的三种测试:
n 文件状态测试(经常使用的)
-d 测试是否文件夹
-f 测试是否通常文件
-L 测试是否连接文件
-r 测试文件是否可读
-w 测试文件是否可写
-x 测试文件是否可执行
-s 测试文件是否非空
n 字符串测试
五种格式: test “string”
test string_operator “string”
test “string” string_operator “string”
[ string_operator “string” ]
[ “string” string_operator “string” ]
其中string_operator能够为: = 两字符串相等
!= 两字符串不等
-z 空串
-n 非空串
n 数值测试
两种格式: “number” number_operator “number”
[ “number” number_operator “number” ]
其中:number_operator 能够为:-eq 、-ne、-gt、-lt、-ge
例如: NUMBER=130
[ “990” –le “995” –a “NUMBER” -gt “133” ]
(其中-a表示先后结果相“与”)
l expr命令通常用于整数值,但也能够用于字符串。
n 格式: expr srgument operator operator argument
例如: expr 10 + 10
expr 10 ^ 2 (10的平方)
expr $value + 10
n 增量计数――expr在循环中最基本的用法
例如: LOOP=0
LOOP=`expr $LOOP + 1`
n 模式匹配:经过指定的冒号选项计算字符串中的字符数
例如: value=account.doc
expr $value : `\(.*\).doc`
输出 account
&& 成功执行一个命令后再执行下一个
|| 一个命令执行失败后再执行另外一个命令
( ) 在当前shell中执行一组命令(格式:(命令1;命令2; ……))
{ } 同( )
例如: comet mouth_end || ( echo “hello” | mail dave ;exit )
若是没有( ),则shell将直接执行最后一个命令(exit)
最有用的调试脚本的工具是echo命令,能够随时打印有关变量或操做的信息,以帮助定位错误。也可以使用打印最后状态($?) 命令来判断命令是否成功,这时要注意的是要在执行完要测试的命令后当即输出$?,不然$?将会改变。
Set命令也能够用来辅助脚本测试:
Set –n 读命令可是不执行
Set –v 显示读取的全部的行
Set –x 显示全部的命令及其参数
(要关闭set选项,只要把-换成+就能够了,这里有点特殊,要注意一下)
command << dilimiter
……
……
dilimiter
以分界符号dilimiter中的内容做为命令的标准输入
经常使用在echo命令中,这样就避免了没输出一行就要使用一个echo命令,同时,输出格式的调整也相应变得简单了。
例如: echo << something_message
************************************************
hello, welcome to use my shell script
************************************************
something_message
将在屏幕上输出:
************************************************
hello, welcome to use my shell script
************************************************
1、利用<<的分解符号性质还能够自动选择菜单或实现自动的ftp传输
也就是利用分解符号的性质自动选择菜单。
例如: ./menu_choose >>output_file 2>&1 <<Choose
2
3
Y
Choose
则自动在执行脚本的过程当中一步步做出选择:2,3,Y
<<这种性质决定了它是理想的访问数据库的有用工具,能够用它来输入面对数据库提示时所做的各类选择。
执行 > file_name 命令或 touch file_name 命令。
$# 传递到脚本的参数个数
$* 以一个单字符串显示全部向脚本传递的参数(可大于9个)
$$ 脚本运行的当前进程的ID号
$! 后台运行的最后一个进程的ID号
$@ 与$#相同,但使用时加引号,并在引号中返回每一个参数
$- 显示shell使用的当前选项
$? 显示最后命令的退出状态,0表示无错误(这个变量也经常用来打印输出,在脚本调试时标记某个shell命令或某个函数是否正确执行,可是要注意,$?记载的是最近的函数或命令的退出状态,所以打印时应该当即打印以得到正确的信息)
在变量中有一种位置变量$n,用来存放函数调用或脚本执行时传入的参数,其中$0表示函数名或脚本名,须要注意的是,这时的脚本名传递的是包含全路径的脚本名。从$1-$9表示传入的第一到第九个参数,这样的参数表示不能多于九个,若是多于九个,能够使用下面将要提到的shift指令来读取。
由于$0存放函数名或脚本名,所以咱们能够经过echo $0来输出调用信息,可是,因为存放的是全路径名,咱们能够利用一个shell命令来获得脚本名,basename $0 将获得$0中名字的部分,而与之相反的,dirname $0将获得$0中路径的部分。
例如:查阅文件前20行: head –20 file_name
查阅文件后10行: tail –10 file_name
awk 是一种很棒的语言。awk 适合于文本处理和报表生成,它还有许多精心设计的特性,容许进行须要特殊技巧程序设计。与某些语言不一样,awk 的语法较为常见。它借鉴了某些语言的一些精华部分,如 C 语言、python 和 bash(虽然在技术上,awk 比 python 和 bash 早建立)。awk 是那种一旦学会了就会成为您战略编码库的主要部分的语言。
让咱们继续,开始使用 awk,以了解其工做原理。在命令行中输入如下命令:
$ awk '{ print }' /etc/passwd
您将会见到 /etc/passwd 文件的内容出如今眼前。如今,解释 awk 作了些什么。调用 awk 时,咱们指定 /etc/passwd 做为输入文件。执行 awk 时,它依次对 /etc/passwd 中的每一行执行 print 命令。全部输出都发送到 stdout,所获得的结果与与执行catting /etc/passwd彻底相同。
如今,解释 { print } 代码块。在 awk 中,花括号用于将几块代码组合到一块儿,这一点相似于 C 语言。在代码块中只有一条 print 命令。在 awk 中,若是只出现 print 命令,那么将打印当前行的所有内容。
这里是另外一个 awk 示例,它的做用与上例彻底相同:
$ awk '{ print $0 }' /etc/passwd
在 awk 中,$0 变量表示整个当前行,因此 print 和 print $0 的做用彻底同样。
若是您愿意,能够建立一个 awk 程序,让它输出与输入数据彻底无关的数据。如下是一个示例:
$ awk '{ print "" }' /etc/passwd
只要将 "" 字符串传递给 print 命令,它就会打印空白行。若是测试该脚本,将会发现对于 /etc/passwd 文件中的每一行,awk 都输出一个空白行。再次说明, awk 对输入文件中的每一行都执行这个脚本。如下是另外一个示例:
$ awk '{ print "hiya" }' /etc/passwd
运行这个脚本将在您的屏幕上写满 hiya。:)
awk 很是善于处理分红多个逻辑字段的文本,并且让您能够绝不费力地引用 awk 脚本中每一个独立的字段。如下脚本将打印出您的系统上全部用户账户的列表:
$ awk -F":" '{ print $1 }' /etc/passwd
上例中,在调用 awk 时,使用 -F 选项来指定 ":" 做为字段分隔符。awk 处理 print $1 命令时,它会打印出在输入文件中每一行中出现的第一个字段。如下是另外一个示例:
$ awk -F":" '{ print $1 $3 }' /etc/passwd
如下是该脚本输出的摘录:
halt7
operator11
root0
shutdown6
sync5
bin1
....etc.
如您所见,awk 打印出 /etc/passwd 文件的第一和第三个字段,它们正好分别是用户名和用户标识字段。如今,当脚本运行时,它并不理想 -- 在两个输出字段之间没有空格!若是习惯于使用 bash 或 python 进行编程,那么您会期望 print $1 $3 命令在两个字段之间插入空格。然而,当两个字符串在 awk 程序中彼此相邻时,awk 会链接它们但不在它们之间添加空格。如下命令会在这两个字段中插入空格:
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
以这种方式调用 print 时,它将链接 $一、" " 和 $3,建立可读的输出。固然,若是须要的话,咱们还能够插入一些文本标签:
$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
这将产生如下输出:
username: halt uid:7
username: operator uid:11
username: root uid:0
username: shutdown uid:6
username: sync uid:5
username: bin uid:1
....etc.
将脚本做为命令行自变量传递给 awk 对于小的单行程序来讲是很是简单的,而对于多行程序,它就比较复杂。您确定想要在外部文件中撰写脚本。而后能够向 awk 传递 -f 选项,以向它提供此脚本文件:
$ awk -f myscript.awk myfile.in
将脚本放入文本文件还可让您使用附加 awk 功能。例如,这个多行脚本与前面的单行脚本的做用相同,它们都打印出 /etc/passwd 中每一行的第一个字段:
BEGIN {
FS=":"
}
{ print $1 }
这两个方法的差异在于如何设置字段分隔符。在这个脚本中,字段分隔符在代码自身中指定(经过设置 FS 变量),而在前一个示例中,经过在命令行上向 awk 传递 -F":" 选项来设置 FS。一般,最好在脚本自身中设置字段分隔符,只是由于这表示您能够少输入一个命令行自变量。咱们将在本文的后面详细讨论 FS 变量。
一般,对于每一个输入行,awk 都会执行每一个脚本代码块一次。然而,在许多编程状况中,可能须要在 awk 开始处理输入文件中的文本以前执行初始化代码。对于这种状况,awk 容许您定义一个 BEGIN 块。咱们在前一个示例中使用了 BEGIN 块。由于 awk 在开始处理输入文件以前会执行 BEGIN 块,所以它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它在程序中之后会引用的全局变量的极佳位置。
awk 还提供了另外一个特殊块,叫做 END 块。awk 在处理了输入文件中的全部行以后执行这个块。一般,END 块用于执行最终计算或打印应该出如今输出流结尾的摘要信息。
awk 容许使用规则表达式,根据规则表达式是否匹配当前行来选择执行独立代码块。如下示例脚本只输出包含字符序列 foo 的那些行:
/foo/ { print }
固然,能够使用更复杂的规则表达式。如下脚本将只打印包含浮点数的行:
/[0-9]+\.[0-9]*/ { print }
还有许多其它方法能够选择执行代码块。咱们能够将任意一种布尔表达式放在一个代码块以前,以控制什么时候执行某特定块。仅当对前面的布尔表达式求值为真时,awk 才执行代码块。如下示例脚本输出将输出其第一个字段等于 fred 的全部行中的第三个字段。若是当前行的第一个字段不等于 fred,awk 将继续处理文件而不对当前行执行 print 语句:
$1 == "fred" { print $3 }
awk 提供了完整的比较运算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 还提供了 "~" 和 "!~" 运算符,它们分别表示“匹配”和“不匹配”。它们的用法是在运算符左边指定变量,在右边指定规则表达式。若是某一行的第五个字段包含字符序列 root,那么如下示例将只打印这一行中的第三个字段:
$5 ~ /root/ { print $3 }
awk 还提供了很是好的相似于 C 语言的 if 语句。若是您愿意,能够使用 if 语句重写前一个脚本:
{
if ( $5 ~ /root/ ) {
print $3
}
}
这两个脚本的功能彻底同样。第一个示例中,布尔表达式放在代码块外面。而在第二个示例中,将对每个输入行执行代码块,并且咱们使用 if 语句来选择执行 print 命令。这两个方法均可以使用,能够选择最适合脚本其它部分的一种方法。
如下是更复杂的 awk if 语句示例。能够看到,尽管使用了复杂、嵌套的条件语句,if 语句看上去仍与相应的 C 语言 if 语句同样:
{
if ( $1 == "foo" ) {
if ( $2 == "foo" ) {
print "uno"
} else {
print "one"
}
} else if ($1 == "bar" ) {
print "two"
} else {
print "three"
}
}
使用 if 语句还能够将代码:
! /matchme/ { print $1 $3 $4 }
转换成:
{
if ( $0 !~ /matchme/ ) {
print $1 $3 $4
}
}
这两个脚本都只输出不包含 matchme 字符序列的那些行。此外,还能够选择最适合您的代码的方法。它们的功能彻底相同。
awk 还容许使用布尔运算符 "||"(逻辑与)和 "&&"(逻辑或),以便建立更复杂的布尔表达式:
( $1 == "foo" ) && ( $2 == "bar" ) { print }
这个示例只打印第一个字段等于 foo 且第二个字段等于 bar 的那些行。
至今,咱们不是打印字符串、整行就是特定字段。然而,awk 还容许咱们执行整数和浮点运算。经过使用数学表达式,能够很方便地编写计算文件中空白行数量的脚本。如下就是这样一个脚本:
BEGIN { x=0 }
/^$/ { x=x+1 }
END { print "I found " x " blank lines. :}" }
在 BEGIN 块中,将整数变量 x 初始化成零。而后,awk 每次遇到空白行时,awk 将执行 x=x+1 语句,递增 x。处理完全部行以后,执行 END 块,awk 将打印出最终摘要,指出它找到的空白行数量。
awk 的优势之一就是“简单和字符串化”。我认为 awk 变量“字符串化”是由于全部 awk 变量在内部都是按字符串形式存储的。同时,awk 变量是“简单的”,由于能够对它执行数学操做,且只要变量包含有效数字字符串,awk 会自动处理字符串到数字的转换步骤。要理解个人观点,请研究如下这个示例:
x="1.01"
# We just set x to contain the *string* "1.01"
x=x+1
# We just added one to a *string*
print x
# Incidentally, these are comments :)
awk 将输出:
2.01
有趣吧!虽然将字符串值 1.01 赋值给变量 x,咱们仍然能够对它加一。但在 bash 和 python 中却不能这样作。首先,bash 不支持浮点运算。并且,若是 bash 有“字符串化”变量,它们并不“简单”;要执行任何数学操做,bash 要求咱们将数字放到丑陋的 $( ) ) 结构中。若是使用 python,则必须在对 1.01 字符串执行任何数学运算以前,将它转换成浮点值。虽然这并不困难,但它还是附加的步骤。若是使用 awk,它是全自动的,而那会使咱们的代码又好又整洁。若是想要对每一个输入行的第一个字段乘方并加一,能够使用如下脚本:
{ print ($1^2)+1 }
若是作一个小实验,就能够发现若是某个特定变量不包含有效数字,awk 在对数学表达式求值时会将该变量看成数字零处理。
awk 的另外一个优势是它有完整的数学运算符集合。除了标准的加、减、乘、除,awk 还容许使用前面演示过的指数运算符 "^"、模(余数)运算符 "%" 和其它许多从 C 语言中借入的易于使用的赋值操做符。
这些运算符包括先后加减(i++、--foo)、加/减/乘/除赋值运算符( a+=三、b*=二、c/=2.二、d-=6.2)。不只如此 -- 咱们还有易于使用的模/指数赋值运算符(a^=二、b%=4)。
awk 有它本身的特殊变量集合。其中一些容许调整 awk 的运行方式,而其它变量能够被读取以收集关于输入的有用信息。咱们已经接触过这些特殊变量中的一个,FS。前面已经提到过,这个变量让您能够设置 awk 要查找的字段之间的字符序列。咱们使用 /etc/passwd 做为输入时,将 FS 设置成 ":"。当这样作有问题时,咱们还能够更灵活地使用 FS。
FS 值并无被限制为单一字符;能够经过指定任意长度的字符模式,将它设置成规则表达式。若是正在处理由一个或多个 tab 分隔的字段,您可能但愿按如下方式设置 FS:
FS="\t+"
以上示例中,咱们使用特殊 "+" 规则表达式字符,它表示“一个或多个前一字符”。
若是字段由空格分隔(一个或多个空格或 tab),您可能想要将 FS 设置成如下规则表达式:
FS="[[:space:]+]"
这个赋值表达式也有问题,它并不是必要。为何?由于缺省状况下,FS 设置成单一空格字符,awk 将这解释成表示“一个或多个空格或 tab”。在这个特殊示例中,缺省 FS 设置偏偏是您最想要的!
复杂的规则表达式也不成问题。即便您的记录由单词 "foo" 分隔,后面跟着三个数字,如下规则表达式仍容许对数据进行正确的分析:
FS="foo[0-9][0-9][0-9]"
接着咱们要讨论的两个变量一般并非须要赋值的,而是用来读取以获取关于输入的有用信息。第一个是 NF 变量,也叫作“字段数量”变量。awk 会自动将该变量设置成当前记录中的字段数量。能够使用 NF 变量来只显示某些输入行:
NF == 3 { print "this particular record has three fields: " $0 }
固然,也能够在条件语句中使用 NF 变量,以下:
{
if ( NF > 2 ) {
print $1 " " $2 ":" $3
}
}
记录号 (NR) 是另外一个方便的变量。它始终包含当前记录的编号(awk 将第一个记录算做记录号 1)。迄今为止,咱们已经处理了每一行包含一个记录的输入文件。对于这些状况,NR 还会告诉您当前行号。然而,当咱们在本系列之后部分中开始处理多行记录时,就不会再有这种状况,因此要注意!能够象使用 NF 变量同样使用 NR 来只打印某些输入行:
(NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" }
另外一个示例:
{
#skip header
if ( NR > 10 ) {
print "ok, now for the real information!"
}
}
awk 提供了适合各类用途的附加变量。咱们将在之后的文章中讨论这些变量。
awk 是一种用于读取和处理结构化数据(如系统的 /etc/passwd 文件)的极佳工具。/etc/passwd 是 UNIX 用户数据库,而且是用冒号定界的文本文件,它包含许多重要信息,包括全部现有用户账户和用户标识,以及其它信息。在个人前一篇文章中,我演示了 awk 如何轻松地分析这个文件。咱们只须将 FS(字段分隔符)变量设置成 ":"。
正确设置了 FS 变量以后,就能够将 awk 配置成分析几乎任何类型的结构化数据,只要这些数据是每行一个记录。然而,若是要分析占据多行的记录,仅仅依靠设置 FS 是不够的。在这些状况下,咱们还须要修改 RS 记录分隔符变量。RS 变量告诉 awk 当前记录何时结束,新记录何时开始。
譬如,让咱们讨论一下如何完成处理“联邦证人保护计划”所涉及人员的地址列表的任务:
Jimmy the Weasel
100 Pleasant Drive
San Francisco, CA 12345
Big Tony
200 Incognito Ave.
Suburbia, WA 67890
理论上,咱们但愿 awk 将每 3 行看做是一个独立的记录,而不是三个独立的记录。若是 awk 将地址的第一行看做是第一个字段 ($1),街道地址看做是第二个字段 ($2),城市、州和邮政编码看做是第三个字段 $3,那么这个代码就会变得很简单。如下就是咱们想要获得的代码:
BEGIN {
FS="\n"
RS=""
}
在上面这段代码中,将 FS 设置成 "\n" 告诉 awk 每一个字段都占据一行。经过将 RS 设置成 "",还会告诉 awk 每一个地址记录都由空白行分隔。一旦 awk 知道是如何格式化输入的,它就能够为咱们执行全部分析工做,脚本的其他部分很简单。让咱们研究一个完整的脚本,它将分析这个地址列表,并将每一个记录打印在一行上,用逗号分隔每一个字段。
address.awk BEGIN {
FS="\n"
RS=""
}
{
print $1 ", " $2 ", " $3
}
若是这个脚本保存为 address.awk,地址数据存储在文件 address.txt 中,能够经过输入 "awk -f address.awk address.txt" 来执行这个脚本。此代码将产生如下输出:
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
在 address.awk 的 print 语句中,能够看到 awk 会链接(合并)一行中彼此相邻的字符串。咱们使用此功能在同一行上的三个字段之间插入一个逗号和空格 (", ")。这个方法虽然有用,但比较难看。与其在字段间插入 ", " 字符串,倒不如让经过设置一个特殊 awk 变量 OFS,让 awk 完成这件事。请参考下面这个代码片段。
print "Hello", "there", "Jim!"
这行代码中的逗号并非实际文字字符串的一部分。事实上,它们告诉 awk "Hello"、"there" 和 "Jim!" 是单独的字段,而且应该在每一个字符串之间打印 OFS 变量。缺省状况下,awk 产生如下输出:
Hello there Jim!
这是缺省状况下的输出结果,OFS 被设置成 " ",单个空格。不过,咱们能够方便地从新定义 OFS,这样 awk 将插入咱们中意的字段分隔符。如下是原始 address.awk 程序的修订版,它使用 OFS 来输出那些中间的 ", " 字符串:
address.awk 的修订版 BEGIN {
FS="\n"
RS=""
OFS=", "
}
{
print $1, $2, $3
}
awk 还有一个特殊变量 ORS,全称是“输出记录分隔符”。经过设置缺省为换行 ("\n") 的 OFS,咱们能够控制在 print 语句结尾自动打印的字符。缺省 ORS 值会使 awk 在新行中输出每一个新的 print 语句。若是想使输出的间隔翻倍,能够将 ORS 设置成 "\n\n"。或者,若是想要用单个空格分隔记录(而不换行),将 ORS 设置成 " "。
假设咱们编写了一个脚本,它将地址列表转换成每一个记录一行,且用 tab 定界的格式,以便导入电子表格。使用稍加修改的 address.awk 以后,就能够清楚地看到这个程序只适合于三行的地址。若是 awk 遇到如下地址,将丢掉第四行,而且不打印该行:
Cousin Vinnie
Vinnie's Auto Shop
300 City Alley
Sosueme, OR 76543
要处理这种状况,代码最好考虑每一个字段的记录数量,并依次打印每一个记录。如今,代码只打印地址的前三个字段。如下就是咱们想要的一些代码:
适合具备任意多字段的地址的 address.awk 版本 BEGIN {
FS="\n"
RS=""
ORS=""
}
{
x=1
while ( x<NF ) {
print $x "\t"
x++
}
print $NF "\n"
}
首先,将字段分隔符 FS 设置成 "\n",将记录分隔符 RS 设置成 "",这样 awk 能够象之前同样正确分析多行地址。而后,将输出记录分隔符 ORS 设置成 "",它将使 print 语句在每一个调用结尾不输出新行。这意味着若是但愿任何文本重新的一行开始,那么须要明确写入 print "\n"。
在主代码块中,建立了一个变量 x 来存储正在处理的当前字段的编号。起初,它被设置成 1。而后,咱们使用 while 循环(一种 awk 循环结构,等同于 C 语言中的 while 循环),对于全部记录(最后一个记录除外)重复打印记录和 tab 字符。最后,打印最后一个记录和换行;此外,因为将 ORS 设置成 "",print 将不输出换行。程序输出以下,这正是咱们所指望的(不算漂亮,但用 tab 定界,以便于导入电子表格):
Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345
Big Tony 200 Incognito Ave. Suburbia, WA 67890
Cousin Vinnie Vinnie's Auto Shop 300 City Alley Sosueme, OR 76543
咱们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。awk 还有 "do...while" 循环,它在代码块结尾处对条件求值,而不象标准 while 循环那样在开始处求值。它相似于其它语言中的 "repeat...until" 循环。如下是一个示例:
do...while 示例 {
count=1
do {
print "I get printed at least once no matter what"
} while ( count != 1 )
}
与通常的 while 循环不一样,因为在代码块以后对条件求值,"do...while" 循环永远都至少执行一次。换句话说,当第一次遇到普通 while 循环时,若是条件为假,将永远不执行该循环。
awk 容许建立 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:
for ( initial assignment; comparison; increment ) {
code block
}
如下是一个简短示例:
for ( x = 1; x <= 4; x++ ) {
print "iteration",x
}
此段代码将打印:
iteration 1
iteration 2
iteration 3
iteration 4
此外,如同 C 语言同样,awk 提供了 break 和 continue 语句。使用这些语句能够更好地控制 awk 的循环结构。如下是迫切须要 break 语句的代码片段:
while 死循环 while (1) {
print "forever and ever..."
}
由于 1 永远表明是真,这个 while 循环将永远运行下去。如下是一个只执行十次的循环:
break 语句示例 x=1
while(1) {
print "iteration",x
if ( x == 10 ) {
break
}
x++
}
这里,break 语句用于“逃出”最深层的循环。"break" 使循环当即终止,并继续执行循环代码块后面的语句。
continue 语句补充了 break,其做用以下:
x=1
while (1) {
if ( x == 4 ) {
x++
continue
}
print "iteration",x
if ( x > 20 ) {
break
}
x++
}
这段代码打印 "iteration 1" 到 "iteration 21","iteration 4" 除外。若是迭代等于 4,则增长 x 并调用 continue 语句,该语句当即使 awk 开始执行下一个循环迭代,而不执行代码块的其他部分。如同 break 同样,continue 语句适合各类 awk 迭代循环。在 for 循环主体中使用时,continue 将使循环控制变量自动增长。如下是一个等价循环:
for ( x=1; x<=21; x++ ) {
if ( x == 4 ) {
continue
}
print "iteration",x
}
在 while 循环中时,在调用 continue 以前没有必要增长 x,由于 for 循环会自动增长 x。
数组
若是您知道 awk 能够使用数组,您必定会感到高兴。然而,在 awk 中,数组下标一般从 1 开始,而不是 0:
myarray[1]="jim"
myarray[2]=456
awk 遇到第一个赋值语句时,它将建立 myarray,并将元素 myarray[1] 设置成 "jim"。执行了第二个赋值语句后,数组就有两个元素了。
数组迭代
定义以后,awk 有一个便利的机制来迭代数组元素,以下所示:
for ( x in myarray ) {
print myarray[x]
}
这段代码将打印数组 myarray 中的每个元素。当对于 for 使用这种特殊的 "in" 形式时,awk 将 myarray 的每一个现有下标依次赋值给 x(循环控制变量),每次赋值之后都循环一次循环代码。虽然这是一个很是方便的 awk 功能,但它有一个缺点 -- 当 awk 在数组下标之间轮转时,它不会依照任何特定的顺序。那就意味着咱们不能知道以上代码的输出是:
jim
456
仍是:
456
jim
套用 Forrest Gump 的话来讲,迭代数组内容就像一盒巧克力 -- 您永远不知道将会获得什么。所以有必要使 awk 数组“字符串化”,咱们如今就来研究这个问题。
在个人前一篇文章中,我演示了 awk 实际上以字符串格式来存储数字值。虽然 awk 要执行必要的转换来完成这项工做,但它却能够使用某些看起来很奇怪的代码:
a="1"
b="2"
c=a+b+3
执行了这段代码后,c 等于 6。因为 awk 是“字符串化”的,添加字符串 "1" 和 "2" 在功能上并不比添加数字 1 和 2 难。这两种状况下,awk 均可以成功执行运算。awk 的“字符串化”性质很是可爱 -- 您可能想要知道若是使用数组的字符串下标会发生什么状况。例如,使用如下代码:
myarr["1"]="Mr. Whipple"
print myarr["1"]
能够预料,这段代码将打印 "Mr. Whipple"。但若是去掉第二个 "1" 下标中的引号,状况又会怎样呢?
myarr["1"]="Mr. Whipple"
print myarr[1]
猜测这个代码片段的结果比较难。awk 将 myarr["1"] 和 myarr[1] 看做数组的两个独立元素,仍是它们是指同一个元素?答案是它们指的是同一个元素,awk 将打印 "Mr. Whipple",如同第一个代码片段同样。虽然看上去可能有点怪,但 awk 在幕后却一直使用数组的字符串下标!
了解了这个奇怪的真相以后,咱们中的一些人可能想要执行相似于如下的古怪代码:
myarr["name"]="Mr. Whipple"
print myarr["name"]
这段代码不只不会产生错误,并且它的功能与前面的示例彻底相同,也将打印 "Mr. Whipple"!能够看到,awk 并无限制咱们使用纯整数下标;若是咱们愿意,能够使用字符串下标,并且不会产生任何问题。只要咱们使用非整数数组下标,如 myarr["name"],那么咱们就在使用关联数组。从技术上讲,若是咱们使用字符串下标,awk 的后台操做并无什么不一样(由于即使使用“整数”下标,awk 仍是会将它看做是字符串)。可是,应该将它们称做关联数组 -- 它听起来很酷,并且会给您的上司留下印象。字符串化下标是咱们的小秘密。;)
谈到数组时,awk 给予咱们许多灵活性。能够使用字符串下标,并且不须要连续的数字序列下标(例如,能够定义 myarr[1] 和 myarr[1000],但不定义其它全部元素)。虽然这些都颇有用,但在某些状况下,会产生混淆。幸亏,awk 提供了一些实用功能有助于使数组变得更易于管理。
首先,能够删除数组元素。若是想要删除数组 fooarray 的元素 1,输入:
delete fooarray[1]
并且,若是想要查看是否存在某个特定数组元素,能够使用特殊的 "in" 布尔运算符,以下所示:
if ( 1 in fooarray ) {
print "Ayep! It's there."
} else {
print "Nope! Can't find it."
}
虽然大多数状况下 awk 的 print 语句能够完成任务,但有时咱们还须要更多。在那些状况下,awk 提供了两个咱们熟知的老朋友 printf() 和 sprintf()。是的,如同其它许多 awk 部件同样,这些函数等同于相应的 C 语言函数。printf() 会将格式化字符串打印到 stdout,而 sprintf() 则返回能够赋值给变量的格式化字符串。若是不熟悉 printf() 和 sprintf(),介绍 C 语言的文章可让您迅速了解这两个基本打印函数。在 Linux 系统上,能够输入 "man 3 printf" 来查看 printf() 帮助页面。
如下是一些 awk sprintf() 和 printf() 的样本代码。能够看到,它们几乎与 C 语言彻底相同。
x=1
b="foo"
printf("%s got a %d on the last test\n","Jim",83)
myout=("%s-%d",b,x)
print myout
此代码将打印:
Jim got a 83 on the last test
foo-1
awk 有许多字符串函数,这是件好事。在 awk 中,确实须要字符串函数,由于不能象在其它语言(如 C、C++ 和 Python)中那样将字符串看做是字符数组。例如,若是执行如下代码:
mystring="How are you doing today?"
print mystring[3]
将会接收到一个错误,以下所示:
awk: string.gawk:59: fatal: attempt to use scalar as array
噢,好吧。虽然不象 Python 的序列类型那样方便,但 awk 的字符串函数仍是能够完成任务。让咱们来看一下。
首先,有一个基本 length() 函数,它返回字符串的长度。如下是它的使用方法:
print length(mystring)
此代码将打印值:
24
好,继续。下一个字符串函数叫做 index,它将返回子字符串在另外一个字符串中出现的位置,若是没有找到该字符串则返回 0。使用 mystring,能够按如下方法调用它:
print index(mystring,"you")
awk 会打印:
9
让咱们继续讨论另外两个简单的函数,tolower() 和 toupper()。与您猜测的同样,这两个函数将返回字符串而且将全部字符分别转换成小写或大写。请注意,tolower() 和 toupper() 返回新的字符串,不会修改原来的字符串。这段代码:
print tolower(mystring)
print toupper(mystring)
print mystring
……将产生如下输出:
how are you doing today?
HOW ARE YOU DOING TODAY?
How are you doing today?
到如今为止一切不错,但咱们究竟如何从字符串中选择子串,甚至单个字符?那就是使用 substr() 的缘由。如下是 substr() 的调用方法:
mysub=substr(mystring,startpos,maxlen)
mystring 应该是要从中抽取子串的字符串变量或文字字符串。startpos 应该设置成起始字符位置,maxlen 应该包含要抽取的字符串的最大长度。请注意,我说的是最大长度;若是 length(mystring) 比 startpos+maxlen 短,那么获得的结果就会被截断。substr() 不会修改原始字符串,而是返回子串。如下是一个示例:
print substr(mystring,9,3)
awk 将打印:
you
若是您一般用于编程的语言使用数组下标访问部分字符串(以及不使用这种语言的人),请记住 substr() 是 awk 代替方法。须要使用它来抽取单个字符和子串;由于 awk 是基于字符串的语言,因此会常常用到它。
首先是 match()。match() 与 index() 很是类似,它与 index() 的区别在于它并不搜索子串,它搜索的是规则表达式。match() 函数将返回匹配的起始位置,若是没有找到匹配,则返回 0。此外,match() 还将设置两个变量,叫做 RSTART 和 RLENGTH。RSTART 包含返回值(第一个匹配的位置),RLENGTH 指定它占据的字符跨度(若是没有找到匹配,则返回 -1)。经过使用 RSTART、RLENGTH、substr() 和一个小循环,能够轻松地迭代字符串中的每一个匹配。如下是一个 match() 调用示例:
print match(mystring,/you/), RSTART, RLENGTH
awk 将打印:
9 9 3
如今,咱们将研究两个字符串替换函数,sub() 和 gsub()。这些函数与目前已经讨论过的函数略有不一样,由于它们确实修改原始字符串。如下是一个模板,显示了如何调用 sub():
sub(regexp,replstring,mystring)
调用 sub() 时,它将在 mystring 中匹配 regexp 的第一个字符序列,而且用 replstring 替换该序列。sub() 和 gsub() 用相同的自变量;惟一的区别是 sub() 将替换第一个 regexp 匹配(若是有的话),gsub() 将执行全局替换,换出字符串中的全部匹配。如下是一个 sub() 和 gsub() 调用示例:
sub(/o/,"O",mystring)
print mystring
mystring="How are you doing today?"
gsub(/o/,"O",mystring)
print mystring
必须将 mystring 复位成其初始值,由于第一个 sub() 调用直接修改了 mystring。在执行时,此代码将使 awk 输出:
HOw are you doing today?
HOw are yOu dOing tOday?
固然,也能够是更复杂的规则表达式。我把测试一些复杂规则表达式的任务留给您来完成。
经过介绍函数 split(),咱们来汇总一下已讨论过的函数。split() 的任务是“切开”字符串,并将各部分放到使用整数下标的数组中。如下是一个 split() 调用示例:
numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")
调用 split() 时,第一个自变量包含要切开文字字符串或字符串变量。在第二个自变量中,应该指定 split() 将填入片断部分的数组名称。在第三个元素中,指定用于切开字符串的分隔符。split() 返回时,它将返回分割的字符串元素的数量。split() 将每个片断赋值给下标从 1 开始的数组,所以如下代码:
print mymonths[1],mymonths[numelements]
……将打印:
Jan Dec
简短注释 -- 调用 length()、sub() 或 gsub() 时,能够去掉最后一个自变量,这样 awk 将对 $0(整个当前行)应用函数调用。要打印文件中每一行的长度,使用如下 awk 脚本:
{
print length()
}
sed 是颇有用(但常被遗忘)的 UNIX 流编辑器。sed是十分强大和小巧的文本流编辑器。使用sed 能够执行字符串替换、建立更大的 sed 脚本以及使用 sed 的附加、插入和更改行命令。在以批处理方式编辑文件或以有效方式建立 shell 脚原本修改现有文件方面,它是十分理想的工具。
sed 经过对输入数据执行任意数量用户指定的编辑操做(“命令”)来工做。sed 是基于行的,所以按顺序对每一行执行命令。而后,sed 将其结果写入标准输出 (stdout),它不修改任何输入文件。
让咱们看一些示例。头几个会有些奇怪,由于我要用它们演示 sed 如何工做,而不是执行任何有用的任务。然而,若是您是 sed 新手,那么理解它们是十分重要的。下面是第一个示例:
$ sed -e 'd' /etc/services
若是输入该命令,将得不到任何输出。那么,发生了什么?在该例中,用一个编辑命令 'd' 调用 sed。sed 打开 /etc/services 文件,将一行读入其模式缓冲区,执行编辑命令(“删除行”),而后打印模式缓冲区(缓冲区已为空)。而后,它对后面的每一行重复这些步骤。这不会产生输出,由于 "d" 命令除去了模式缓冲区中的每一行!
在该例中,还有几件事要注意。首先,根本没有修改 /etc/services。这仍是由于 sed 只读取在命令行指定的文件,将其用做输入 -- 它不试图修改该文件。第二件要注意的事是 sed 是面向行的。'd' 命令不是简单地告诉 sed 一会儿删除全部输入数据。相反,sed 逐行将 /etc/services 的每一行读入其称为模式缓冲区的内部缓冲区。一旦将一行读入模式缓冲区,它就执行 'd' 命令,而后打印模式缓冲区的内容(在本例中没有内容)。我将在后面为您演示如何使用地址范围来控制将命令应用到哪些行 -- 可是,若是不使用地址,命令将应用到全部行。第三件要注意的事是括起 'd' 命令的单引号的用法。养成使用单引号来括起 sed 命令的习惯是个好注意,这样能够禁用 shell 扩展。
下面是使用 sed 从输出流除去 /etc/services 文件第一行的示例:
$ sed -e '1d' /etc/services | more
如您所见,除了前面有 '1' 以外,该命令与第一个 'd' 命令十分相似。若是您猜到 '1' 指的是第一行,那您就猜对了。与第一个示例中只使用 'd' 不一样的是,这一次使用的 'd' 前面有一个可选的数字地址。经过使用地址,能够告诉 sed 只对某一或某些特定行进行编辑。
如今,让咱们看一下如何指定地址范围。在本例中,sed 将删除输出的第 1 到 10 行:
$ sed -e '1,10d' /etc/services | more
当用逗号将两个地址分开时,sed 将把后面的命令应用到从第一个地址开始、到第二个地址结束的范围。在本例中,将 'd' 命令应用到第 1 到 10 行(包括这两行)。全部其它行都被忽略。
如今演示一个更有用的示例。假设要查看 /etc/services 文件的内容,可是对查看其中包括的注释部分不感兴趣。如您所知,能够经过以 '#' 字符开头的行在 /etc/services 文件中放置注释。为了不注释,咱们但愿 sed 删除以 '#' 开始的行。如下是具体作法:
$ sed -e '/^#/d' /etc/services | more
试一下该例,看看发生了什么。您将注意到,sed 成功完成了预期任务。如今,让咱们分析发生的状况:
要理解 '/^#/d' 命令,首先须要对其剖析。首先,让咱们除去 'd' -- 这是咱们前面所使用的同一个删除行命令。新增长的是 '/^#/' 部分,它是一种新的规则表达式地址。规则表达式地址老是由斜杠括起。它们指定一种 模式,紧跟在规则表达式地址以后的命令将仅适用于正好与该特定模式匹配的行。所以,'/^#/' 是一个规则表达式。(规则表达式的有关规定能够参见本文前面的内容)
例如:
$ sed -e '/regexp/d' /path/to/my/test/file | more
这将致使 sed 删除任何匹配的行。
对好比下的命令:
$ sed -n -e '/regexp/p' /path/to/my/test/file | more
请注意新的 '-n' 选项,该选项告诉 sed 除非明确要求打印模式空间,不然不这样作。您还会注意到,咱们用 'p' 命令替换了 'd' 命令,如您所猜测的那样,这明确要求 sed 打印模式空间。就这样,将只打印匹配部分。
目前为止,咱们已经看到了行地址、行范围地址和 regexp 地址。可是,还有更多的可能。咱们能够指定两个用逗号分开的规则表达式,sed 将与全部从匹配第一个规则表达式的第一行开始,到匹配第二个规则表达式的行结束(包括该行)的全部行匹配。
例如,如下命令将打印从包含 "BEGIN" 的行开始,而且以包含 "END" 的行结束的文本块:
$ sed -n -e '/BEGIN/,/END/p' /my/test/file | more
若是没发现 "BEGIN",那么将不打印数据。若是发现了 "BEGIN",可是在这以后的全部行中都没发现 "END",那么将打印全部后续行。发生这种状况是由于 sed 面向流的特性 -- 它不知道是否会出现 "END"。
C 源代码示例
若是只要打印 C 源文件中的 main() 函数,可输入:
$ sed -n -e '/main[[:space:]]*(/,/^)/p' sourcefile.c | more
该命令有两个规则表达式 '/main[[:space:]]*(/' 和 '/^}/',以及一个命令 'p'。第一个规则表达式将与后面依次跟有任意数量的空格或制表键以及开始圆括号的字符串 "main" 匹配。这应该与通常 ANSI C main() 声明的开始匹配。
在这个特别的规则表达式中,出现了 '[[:space:]]' 字符类。这只是一个特殊的关键字,它告诉 sed 与 TAB 或空格匹配。若是愿意的话,能够不输入 '[[:space:]]',而输入 '[',而后是空格字母,而后是 -V,而后再输入制表键字母和 ']' -- Control-V 告诉 bash 要插入“真正”的制表键,而不是执行命令扩展。使用 '[[:space:]]' 命令类(特别是在脚本中)会更清楚。
如今看一下第二个 regexp。'/^}' 将与任何出如今新行行首的 '}' 字符匹配。若是代码的格式很好,那么这将与 main() 函数的结束花括号匹配。若是格式很差,则不会正确匹配 -- 这是执行模式匹配任务的一件棘手之事。由于是处于 '-n' 安静方式,因此 'p' 命令仍是完成其惯有任务,即明确告诉 sed 打印该行。试着对 C 源文件运行该命令 -- 它应该输出整个 main() { } 块,包括开始的 "main()" 和结束的 '}'。
让咱们看一下 sed 最有用的命令之一,替换命令。使用该命令,能够将特定字符串或匹配的规则表达式用另外一个字符串替换。
下面是该命令最基本用法的示例:
$ sed -e 's/foo/bar/' myfile.txt
上面的命令将 myfile.txt 中每行第一次出现的 'foo'(若是有的话)用字符串 'bar' 替换,而后将该文件内容输出到标准输出。请注意,我说的是每行第一次出现,尽管这一般不是您想要的。在进行字符串替换时,一般想执行全局替换。也就是说,要替换每行中的全部出现,以下所示:
$ sed -e 's/foo/bar/g' myfile.txt
在最后一个斜杠以后附加的 'g' 选项告诉 sed 执行全局替换。
关于 's///' 替换命令,还有其它几件要了解的事。首先,它是一个命令,而且只是一个命令,在全部上例中都没有指定地址。这意味着,'s///' 还能够与地址一块儿使用来控制要将命令应用到哪些行,以下所示:
$ sed -e '1,10s/enchantment/entrapment/g' myfile2.txt
上例将致使用短语 'entrapment' 替换全部出现的短语 'enchantment',可是只在第一到第十行(包括这两行)上这样作。
$ sed -e '/^$/,/^END/s/hills/mountains/g' myfile3.txt
该例将用 'mountains' 替换 'hills',可是,只从空行开始,到以三个字符 'END' 开始的行结束(包括这两行)的文本块上这样作。
关于 's///' 命令的另外一个妙处是 '/' 分隔符有许多替换选项。若是正在执行字符串替换,而且规则表达式或替换字符串中有许多斜杠,则能够经过在 's' 以后指定一个不一样的字符来更改分隔符。例如,下例将把全部出现的 /usr/local 替换成 /usr:
$ sed -e 's:/usr/local:/usr:g' mylist.txt
在该例中,使用冒号做为分隔符。若是须要在规则表达式中指定分隔符字符,能够在它前面加入反斜杠。
目前为止,咱们只执行了简单的字符串替换。虽然这很方便,可是咱们还能够匹配规则表达式。例如,如下 sed 命令将匹配从 '<' 开始、到 '>' 结束、而且在其中包含任意数量字符的短语。下例将删除该短语(用空字符串替换):
$ sed -e 's/<.*>//g' myfile.html
这是要从文件除去 HTML 标记的第一个很好的 sed 脚本尝试,可是因为规则表达式的特有规则,它不会很好地工做。缘由何在?当 sed 试图在行中匹配规则表达式时,它要在行中查找最长的匹配。在个人前一篇 sed 文章中,这不成问题,由于咱们使用的是 'd' 和 'p' 命令,这些命令总要删除或打印整行。可是,在使用 's///' 命令时,确实有很大不一样,由于规则表达式匹配的整个部分将被目标字符串替换,或者,在本例中,被删除。这意味着,上例将把下行:
<b>This</b> is what <b>I</b> meant.
变成:meant.
咱们要的不是这个,而是:This is what I meant.
幸运的是,有一种简便方法来纠正该问题。咱们不输入“'<' 字符后面跟有一些字符并以 '>' 字符结束”的规则表达式,而只需输入一个“'<' 字符后面跟有任意数量非 '>' 字符并以 '>' 字符结束”的规则表达式。这将与最短、而不是最长的可能性匹配。新命令以下:
$ sed -e 's/<[^>]*>//g' myfile.html
在上例中,'[^>]' 指定“非 '>'”字符,其后的 '*' 完成该表达式以表示“零或多个非 '>' 字符”。对几个 html 文件测试该命令,将它们管道输出到 "more",而后仔细查看其结果。
'[ ]' 规则表达式语法还有一些附加选项。要指定字符范围,只要字符不在第一个或最后一个位置,就能够使用 '-',以下所示:
'[a-x]*'
这将匹配零或多个所有为 'a'、'b'、'c'...'v'、'w'、'x' 的字符。另外,能够使用 '[:space:]' 字符类来匹配空格(字符类的相关信息能够参见本文前面部份内容)。
咱们已经看到如何执行简单甚至有些复杂的直接替换,可是 sed 还能够作更多的事。实际上能够引用匹配规则表达式的部分或所有,并使用这些部分来构造替换字符串。做为示例,假设您正在回复一条消息。下例将在每一行前面加上短语 "ralph said: ":
$ sed -e 's/.*/ralph said: &/' origmsg.txt
输出以下:
ralph said: Hiya Jim, ralph said: ralph said:
I sure like this sed stuff! ralph said:
该例的替换字符串中使用了 '&' 字符,该字符告诉 sed 插入整个匹配的规则表达式。所以,能够将与 '.*' 匹配的任何内容(行中的零或多个字符的最大组或整行)插入到替换字符串中的任何位置,甚至屡次插入。这很是好,但 sed 甚至更强大。
那些极好的带反斜杠的圆括号
's///' 命令甚至比 '&' 更好,它容许咱们在规则表达式中定义区域,而后能够在替换字符串中引用这些特定区域。做为示例,假设有一个包含如下文本的文件:
bar oni eeny meeny miny larry curly moe jimmy the weasel
如今假设要编写一个 sed 脚本,该脚本将把 "eeny meeny miny" 替换成 "Victor eeny-meeny Von miny" 等等。要这样作,首先要编写一个由空格分隔并与三个字符串匹配的规则表达式:
'.* .* .*'
如今,将在其中每一个感兴趣的区域两边插入带反斜杠的圆括号来定义区域:
'\(.*\) \(.*\) \(.*\)'
除了要定义三个可在替换字符串中引用的逻辑区域之外,该规则表达式的工做原理将与第一个规则表达式相同。下面是最终脚本:
$ sed -e 's/\(.*\) \(.*\) \(.*\)/Victor \1-\2 Von \3/' myfile.txt
如您所见,经过输入 '\x'(其中,x 是从 1 开始的区域号)来引用每一个由圆括号定界的区域。输入以下:
Victor foo-bar Von oni Victor eeny-meeny Von miny Victor larry-curly Von moe Victor jimmy-the Von weasel
随着对 sed 愈来愈熟悉,您能够花最小力气来进行至关强大的文本处理。您可能想如何使用熟悉的脚本语言来处理这种问题 -- 能用一行代码轻易实现这样的解决方案吗?
在开始建立更复杂的 sed 脚本时,须要有输入多个命令的能力。有几种方法这样作。首先,能够在命令之间使用分号。例如,如下命令系列使用 '=' 命令和 'p' 命令,'=' 命令告诉 sed 打印行号,'p' 命令明确告诉 sed 打印该行(由于处于 '-n' 模式)。
$ sed -n -e '=;p' myfile.txt
不管何时指定了两个或更多命令,都按顺序将每一个命令应用到文件的每一行。在上例中,首先将 '=' 命令应用到第 1 行,而后应用 'p' 命令。接着,sed 继续处理第 2 行,并重复该过程。虽然分号很方便,可是在某些场合下,它不能正常工做。另外一种替换方法是使用两个 -e 选项来指定两个不一样的命令:
$ sed -n -e '=' -e 'p' myfile.txt
然而,在使用更为复杂的附加和插入命令时,甚至多个 '-e' 选项也不能帮咱们的忙。对于复杂的多行脚本,最好的方法是将命令放入一个单独的文件中。而后,用 -f 选项引用该脚本文件:
$ sed -n -f mycommands.sed myfile.txt
这种方法虽然可能不太方便,但老是管用。
有时,可能要指定应用到一个地址的多个命令。这在执行许多 's///' 以变换源文件中的字和语法时特别方便。要对一个地址执行多个命令,可在文件中输入 sed 命令,而后使用 '{ }' 字符将这些命令分组,以下所示:
1,20{ s/[Ll]inux/GNU\/Linux/g s/samba/Samba/g s/posix/POSIX/g }
上例将把三个替换命令应用到第 1 行到第 20 行(包括这两行)。还能够使用规则表达式地址或者两者的组合:
1,/^END/{ s/[Ll]inux/GNU\/Linux/g s/samba/Samba/g s/posix/POSIX/g p }
该例将把 '{ }' 之间的全部命令应用到从第 1 行开始,到以字母 "END" 开始的行结束(若是在源文件中没发现 "END",则到文件结束)的全部行。
既然在单独的文件中编写 sed 脚本,咱们能够利用附加、插入和更改行命令。这些命令将在当前行以后插入一行,在当前行以前插入一行,或者替换模式空间中的当前行。它们也能够用来将多行插入到输出。插入行命令用法以下:
i\ This line will be inserted before each line
若是不为该命令指定地址,那么它将应用到每一行,并产生以下的输出:
This line will be inserted before each line line 1 here
This line will be inserted before each line line 2 here
This line will be inserted before each line line 3 here
This line will be inserted before each line line 4 here
若是要在当前行以前插入多行,能够经过在前一行以后附加一个反斜杠来添加附加行,以下所示:
i\ insert this line\ and this one\ and this one\ and, uh, this one too.
附加命令的用法与之相似,可是它将把一行或多行插入到模式空间中的当前行以后。其用法以下:
a\ insert this line after each line. Thanks! :)
另外一方面,“更改行”命令将实际替换模式空间中的当前行,其用法以下:
c\ You're history, original line! Muhahaha!
由于附加、插入和更改行命令须要在多行输入,因此将把它们输入到一个文本 sed 脚本中,而后经过使用 '-f' 选项告诉 sed 执行它们。使用其它方法将命令传递给 sed 会出现问题。
这些示例不只演示 sed 的能力,并且还作一些真正巧妙(和方便)的事。例如,在本文的后半部,将为您演示如何设计一个 sed 脚原本将 .QIF 文件从 Intuit 的 Quicken 金融程序转换成具备良好格式的文本文件。在那样作以前,咱们将看一下不怎么复杂但却颇有用的 sed 脚本。
l 文本转换
第一个实际脚本将 UNIX 风格的文本转换成 DOS/Windows 格式。您可能知道,基于 DOS/Windows 的文本文件在每一行末尾有一个 CR(回车)和 LF(换行),而 UNIX 文本只有一个换行。有时可能须要将某些 UNIX 文本移至 Windows 系统,该脚本将为您执行必需的格式转换。
$ sed -e 's/$/\r/' myunix.txt > mydos.txt
在该脚本中,'$' 规则表达式将与行的末尾匹配,而 '\r' 告诉 sed 在其以前插入一个回车。在换行以前插入回车,当即,每一行就以 CR/LF 结束。请注意,仅当使用 GNU sed 3.02.80 或之后的版本时,才会用 CR 替换 '\r'。若是尚未安装 GNU sed 3.02.80,请在个人第一篇 sed 文章中查看如何这样作的说明。
我已记不清有多少次在下载一些示例脚本或 C 代码以后,却发现它是 DOS/Windows 格式。虽然不少程序不在意 DOS/Windows 格式的 CR/LF 文本文件,可是有几个程序却在意 -- 最著名的是 bash,只要一遇到回车,它就会出问题。如下 sed 调用将把 DOS/Windows 格式的文本转换成可信赖的 UNIX 格式:
$ sed -e 's/.$//' mydos.txt > myunix.txt
该脚本的工做原理很简单:替代规则表达式与一行的最末字符匹配,而该字符刚好就是回车。咱们用空字符替换它,从而将其从输出中完全删除。若是使用该脚本并注意到已经删除了输出中每行的最末字符,那么,您就指定了已是 UNIX 格式的文本文件。也就不必那样作了!
l 反转行
下面是另外一个方便的小脚本。与大多数 Linux 发行版中包括的 "tac" 命令同样,该脚本将反转文件中行的次序。"tac" 这个名称可能会给人以误导,由于 "tac" 不反转行中字符的位置(左和右),而是反转文件中行的位置(上和下)。用 "tac" 处理如下文件:
foo bar oni
....将产生如下输出:
oni bar foo
能够用如下 sed 脚本达到相同目的:
$ sed -e '1!G;h;$!d' forward.txt > backward.txt
若是登陆到恰巧没有 "tac" 命令的 FreeBSD 系统,将发现该 sed 脚本颇有用。虽然方便,但最好仍是知道该脚本为何那样作。让咱们对它进行讨论。
反转解释:首先,该脚本包含三个由分号隔开的单独 sed 命令:'1!G'、'h' 和 '$!d'。如今,须要好好理解用于第一个和第三个命令的地址。若是第一个命令是 '1G',则 'G' 命令将只应用第一行。然而,还有一个 '!' 字符 -- 该 '!' 字符忽略该地址,即,'G' 命令将应用到除第一行以外的全部行。'$!d' 命令与之相似。若是命令是 '$d',则将只把 'd' 命令应用到文件中的最后一行('$' 地址是指定最后一行的简单方式)。然而,有了 '!' 以后,'$!d' 将把 'd' 命令应用到除最后一行以外的全部行。如今,咱们所要理解的是这些命令自己作什么。
当对上面的文本文件执行反转脚本时,首先执行的命令是 'h'。该命令告诉 sed 将模式空间(保存正在处理的当前行的缓冲区)的内容复制到保留空间(临时缓冲区)。而后,执行 'd' 命令,该命令从模式空间中删除 "foo",以便在对这一行执行完全部命令以后不打印它。
如今,第二行。在将 "bar" 读入模式空间以后,执行 'G' 命令,该命令将保留空间的内容 ("foo\n") 附加到模式空间 ("bar\n"),使模式空间的内容为 "bar\n\foo\n"。'h' 命令将该内容放回保留空间保护起来,而后,'d' 从模式空间删除该行,以便不打印它。
对于最后的 "oni" 行,除了不删除模式空间的内容(因为 'd' 以前的 '$!')以及将模式空间的内容(三行)打印到标准输出以外,重复一样的步骤。
l #查找当前目录中是否存在指定目录,若不存在,则建立之
function mkdir_1
{
if test ! -d $1
then
mkdir $1
fi
}
l #将指定文件中的"prefix = .*"串替换为"prefix=\/home\/gnome-unicore-install2\/usr/"
#能够用来做为sed用法的参考
function modify_prefix
{
chmod +w $1
cp $1 $1.bak
sed 's/prefix = .*/prefix=\/home\/gnome-unicore-install2\/usr/g' $1.bak > $1
rm $1.bak
}
l #将指定文件中的"^LDFLAGS =.*"串替换为"LDFLAGS = -rdynamic -lgdk_pixbuf -lgtk -lgdk -lgmodule -lglib -ldl -lXext -lX11 -lm"
#change_gnome-config FILENAME
function change_gnome-config
{
cp $1 $1.bak
sed 's/^LDFLAGS =.*/LDFLAGS = -rdynamic -lgdk_pixbuf -lgtk -lgdk -lgmodule -lglib -ldl -lXext -lX11 -lm /g' $1.bak> $1
rm $1.bak
}
l #删除指定文件的含有指定字符的行
#格式:delete_line filename "word_contain"
function delete_line
{
chmod +w $1
cp $1 $1.bak
cat $1.bak | grep -v -e "$2" >$1
}
l #用途:删除文件中包含line1或(和?)line2的行
#格式:delete_line filename line1 line2
function delete_line_no
{
chmod +w $1
cp $1 $1.bak
sed $2,$3'd' $1.bak>$1
rm $1.bak
}
l #用途:在LINE_NO指定的行插入字符串CONTENT
#能够用来做为sed用法的参考
#格式: add_line FILENAME LINE_NO CONTENT
function add_line
{
chmod +w $1
cp $1 $1.bak
sed -e $2 'i\' "$3" '' $1.bak > $1
rm $1.bak
}
l #用途:检查含有"PC24"代码的程序并打印出来
#格式: check_PC24 //after installation
function check_PC24
{
echo "now comes the PC24 checking..."
. $COMMAND_UNICORE/shell/shell_PC24 >& /dev/null
if test -s $COMMAND_UNICORE/PC24_result
then :
echo "The following file contains PC24 problems: $COMMAND_UNICORE/PC24_result "
else
echo "No PC24 problem found"
fi
}
l #打印标题
displayheader() {
echo " *****************************************"
echo " * IeeeCC754 testing tool *"
echo " *****************************************"
echo " "
}
l #打印一个菜单的作法
displayplatformmenu() {
#clear the screen
clear
displayheader
echo " a) SunSparc "
echo " b) IntelPentium "
echo " c) AMD "
echo " d) Unicore32 "
echo " e) Unicore32(with FP2001) "
echo " "
echo -n " select a Platform > "
}
l #接收一个菜单输入
displayplatformmenu
read answer
case ${answer} in
a) TARGET="BasicOp";;
b) TARGET="Conversion";;
*) badchoice;;
esac
l #查找当前目录下是否存在file_name文件
#能够用来做为if用法的参考
detectfile_name() {
if [ ! -f file_name ]
then
echo "Error: file_name does not exist. Please check"
exit 1;
else
echo "OK,the directy is exist"
fi
}
l #将参数指定的一个或多个目录项以及其下的多级子目录下的全部文件名和目录名转换为小写。
cvitem()
{
echo "mv $1 `dirname $1`/`basename $1 | tr \
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`"
}
[ $# = 0 ] && { echo "Usage: lcdir item1 item2 ..."; exit; }
for item in $* #能够用来做为for用法的参考
do
[ "`dirname $item`" != "`basename $item`" ] && {
[ -d $item ] &&
{
for subitem in `ls $item`
do
cvlc $item/$subitem
done
}
cvitem $item
}
done
l #一个login的例子
if ($?path) then
set path=($HOME/bin $path)
else
set path=($HOME/bin /usr/bin .)
endif
if ( ! $ {?DT} ); then
stty dec new
tset -I -Q
endif
set mail=/usr/spool/mail/$USER
l #关于if使用的几个例子
n #执行一个命令或程序以前,先检查该命令是否存在,然後才执行
if [ -x /sbin/quotaon ] ; then
echo "Turning on Quota for root filesystem"
/sbin/quotaon /
fi
n #获得Hostname
#!/bin/sh
if [ -f /etc/HOSTNAME ] ; then
HOSTNAME=`cat /etc/HOSTNAME`
else
HOSTNAME=localhost
fi
n #若是某个设定档容许有好几个位置的话,例如crontab,可利用if then elif fi来找寻
if [ -f /etc/crontab ] ; then #[ -f /etc/crontab ]等价于test -f /etc/crontab
CRONTAB="/etc/crontab"
elif [ -f /var/spool/cron/crontabs/root ] ; then
CRONTAB="/var/spool/cron/crontabs/root"
elif [ -f /var/cron/tabs/root ] ; then
CRONTAB="/var/cron/tabs/root"
fi
export CRONTAB
n #利用uname来判断目前系统,并分别作各系统情况不一样的事。
SYSTEM=`uname -s`
if [ $SYSTEM = "Linux" ] ; then
echo "Linux"
elif [ $SYSTEM = "FreeBSD" ] ; then
echo "FreeBSD"
elif [ $SYSTEM = "Solaris" ] ; then
echo "Solaris"
else
echo "What?"
fi
l #关于while使用的几个例子
n #无条件循环
while : ; do
echo "do something forever here"
sleep 5
done
如下只说明各指令的基本用法, 若需详细说明, 请用 man 去读详细的 manual.
1. ls
这是最基本的文件指令。 ls 的意义为 "list",也就是将某一个目录或是某一个文件的内容显示出来。
若是你在下 ls 指令后面没有跟任何的文件名,它将会显示出目前目录中全部文件。
也能够在 ls 后面加上所要察看的目录名称或文件的名称,如:
% ls /home2/X11R5
% ls first
ls 有一些特别的参数,能够给予使用者更多有关的信息,以下:
-a : 在 UNIX 中若一个目录或文件名字的第一个字符为 "." , 则使用 ls
将不会显示出这个文件的名字,咱们称此类文件为隐藏文件。若是咱们要察看这类文件,则必须加上参数 -a 。
-l : 这个参数表明使用 ls 的长( long )格式,能够显示更多的信息,如文件存取权,文件拥有者( owner ),文件大小,文件最后更新日期,甚而 symbolic link 的文件是 link 到那一个文件等等。例如:
% ls -l
drwx--x--x 2 jjtseng 512 Aug 8 05:08 18
drwx--x--x 2 jjtseng 512 Aug 8 22:00 19
-rw------- 1 jjtseng 566 Aug 8 05:28 makefile
2. cp
cp 这个指令的意义是复制("COPY") , 也就是将一个或多个文件复制成另外一个文件或者是将其复制到另外一个目录去。
cp 的用法以下:
cp f1 f2 : 将文件名为 f1 的文件复制一份为文件名为 f2 的文件。
cp f1 f2 f3 ... dir : 将文件 f1 f2 f3 ... 都以相同的文件名复制一份放到目录 dir 里面。
cp -r dir1 dir2 : 将 dir1 的所有内容所有复制到 dir2 里面。
cp 也有一些参数,以下:
-i : 此参数是当已经有文件名为 f2 的文件时,若迳自使用 cp 将会将原来 f2的内容覆盖,所以在要覆盖以前先询问使用者。如使用者的回答是y(yes)才执行复制的动做。
-r : 此参数是用来作递回复制用,可递归的将整个目录都复制到另外一个目录中。
3. mv
mv 的意义为 move , 主要是将一文件更名或移动到另外一个目录。与cp相似,它也有三种格式:
mv f1 f2 : 将文件名为 f1 的文件变动成文件名为 f2 的文件。
mv dir1 dir2 : 将文件名为 dir1 的目录变动成文件名为 dir2 的目录。
mv f1 f2 f3 ... dir : 将文件 f1 f2 f3 ... 都移至目录 dir 里面。
mv 的参数有两个,-f 和 -i , 其中 -i 的意义与 cp 中的相同,均是 interactive的意思。而 -f 为强迫( force ) , 就是无论有没有同名的文件,反正就是要执行,全部其余的参数遇到 -f 均会失效。
4. rm
rm 的意义是 remove ,也就是用来删除一个文件的指令。须要注意的是,在 UNIX 中一个被删除的文件除非是系统刚好作了备份,不然是没法像 DOS 里面同样还可以恢复的。因此在作 rm 动做的时候使用者应该要特别当心。
rm 的格式以下:
rm f1 f2 f3 .....
rm 的参数比较经常使用的有几个: -f , -i , 与 -r
-f : 将会使得系统在删除时,不提出任何警告讯息。
-i : 在删除文件以前均会询问是否真要删除。
-r : 递归的删除,可用于删除目录。
5. mkdir
mkdir 是一个让使用者创建一个目录的指令。你能够在一个目录底下使用 mkdir 创建一个子目录,使用的方法以下:
mkdir dirname1 [ dirname2 ... ]
8. pwd
pwd 会将当前目录的路径( path )显示出来
9. cat/more/less
以上三个指令均为察看文件内容的指令。cat 的意义是concatenate,实际就是把文件的内容显示出来的意思。
cat 有许多奇怪的参数,较常为人所使用的是 -n 参数,也就是把显示出来的内容加上行号。
cat 的用法以下:
cat [-n] :自标准输入读取内容,能够用 pipe 将别的指令的输出转向给 cat 。
cat [-n] filename : 将 filename 的内容读进来,显示在标准输出上。
问题在於 cat 它是不会停下来的,所以并很差用( 试想若是一个萤幕二十四行,而一个文件四百行,cat 一出来将会噼里啪啦不断的卷上去,使用者很难据此获得他们所需的信息。) 因此经常么使用 more 和less来帮助。
more 可让文件根据控制台的模式一页页的显示出来,再根据使用者的要求换页或者换行。若是使用者要在某一个文件中搜寻一个特定的字符串,则按 / 而后跟着打所要搜寻的单字便可进行搜寻。
more 的使用法以下:
more filename
若是你在使用中以为已经看到了所要看的部份,能够按'q'离开 more 的使用。
less 的用法与 more 极相似,原先它就是为了弥补 more 只能往前方卷页的缺点而设计。
Less 的用法以下:
less filename
它与 more 不一样的是它能够按 y 来往上卷一行,而且能够用"?"来往回搜寻你所要找的字符。
10. chmod
chmod用来改变文件存取模式( change mode ) 。在linux中,一个文件有可读(r)可写(w)可执行(x)三种模式,分别针对该文件的拥有者( onwer )、同组用户( group member )(能够 ls -lg来观看某一文件的所属的 group ),以及其余人( other )。
一个文件若是改为可执行模式则系统就将其视为一个可执行文件,而一个目录的可执行模式表明使用者有进入该目录之权利。
chmod使用方式以下:
chmod [ -fR ] mode filename ...
其参数的意义以下:
-f Force. chmod 不会理会失败的动做。
-R Recurive. 会将目录下全部子目录及文件改成你所要改为的模式。
1. ps
ps 是用来显示目前你的 process 或系统 processes 的情况。
其选项说明以下:
-a 列出包括其余 users 的 process 情况。
-u 显示 user - oriented 的 process 情况 。
-x 显示包括没有 terminal 控制的 process 情况 。
-w 使用较宽的显示模式来显示 process 情况 。
咱们能够经由 ps 取得目前 processes 的情况,如 pid , running state 等。
2. kill
kill 指令的用途是送一个 signal 给某一个 process 。由于大部份送的都是用来杀掉 process 的 SIGKILL 或 SIGHUP,所以称为kill 。
kill 的用法为:
kill [ -SIGNAL ] pid ...
kill -l
SIGNAL 为一个 singal 的数字,从 0 到 31 ,其中 9 是 SIGKILL ,也就是通常用来杀掉一些没法正常 terminate 的信号。
也能够用 kill -l 来察看可代替 signal 号码的数字。
1. echo
echo 是用来显示一字符串在标准输出上。echo -n 则表示当显示完以后不执行换行操做。
2. grep
grep 为一过滤器,它可自一个或多个文件中过滤出具备某个字符串的行,或是从标准输入过滤出具备某个字符串的行。
grep的用法以下:
grep [-nv] match_pattern file1 file2 ....
-n 把所找到的行在行前加上行号列出
-v 把不包含 match_pattern 的行列出
match_pattern 所要搜寻的字符串
-f 以 pattern_file 存放所要搜寻的字符串
1. man
man 是手册 ( manual ) 的意思。 UNIX 提供线上辅助( on-line help )的功能,man 就是用来让使用者在使用时查询指令、系统调用、标准库函数、各类表格等的使用所用的。
man 的用法以下:
man [-M path] [[section] title ] .....
man [-M path] -k keyword ...
-M path man 所须要的 manual database 的路径。咱们也能够用设定环境变数 MANPATH 的方式来取代 -M 选项。
title 这是所要查询的目标。
section 用一个数字表示 manual 的分类,一般 1 表明可执行指令,2 表明系统调用( system call ) ,3 表明标准库函数,等等。
man 在 UNIX 上是一项很是重要的指令,咱们在这里所描述的用法仅仅只是一个你们比较经常使用的用法以及简单的说明,真正详细的用法与说明仍是要经过使用 man 来获得。
2. who
who 指令是用来查询目前有那些人在线上。
3. info
info的查询与man相似。
1. telnet
telnet 是一个提供 user 经过网络连到 remote host。
telnet 的 格式以下:
telnet [ hostname | ip-address ] [ port ]
hostname 为一个像 ccsun1 或是 ccsun1.cc.nctu.edu.tw 的 name address,ip-address 则为一个由四个小于 255 的数字组成的 ip address ,
2. ftp
ftp 的意义是 File Transfer Program ,是一个很经常使用的在网路文件传输的软件。
ftp 的格式以下:
ftp [ hostname | ip-address ]
其中 hostname | ip-address 的意义跟 telnet 中的相同。
在进入 ftp 以后,若是与 remote host 链接上了,它将会询问你 username 与密码,若是输入对了就能够开始进行文件传输。
在 ftp 中有许多的命令,这里仅列出较经常使用的 cd , lcd , mkdir , put , mput , get , mget , binary , ascii , prompt , help 与 quit 的使用方式。
ascii 将传输模式设为 ascii 模式。一般用於传送文字文件。
binary 将传输模式设为 binary 模式,一般用于传送执行文件,压缩文件与影像文件等。
cd remote-directory 将 remote host 上的工做目录改变。
lcd [ directory ] 更改 local host 的工做目录。
ls [ remote-directory ] [ local-file ] 列出 remote host 上的文件。
get remote-file [ local-file ] 取得登录机的文件。
mget remote-files 可以使用通用字符一次取得多个文件。
put local-file [ remote-file] 将 local host 的文件送到 remote host。
mput local-files 可以使用通用字符一次将多个文件放到 remote host 上。
help [ command ] 线上辅助指令。
mkdir directory-name 在 remote host 新建一个目录。
prompt 更改交谈模式,若为 on 则在 mput 与 mget 时每作一个文件传输时均会询问。
Exit/quit离开ftp
3.rlogin命令
rlogin 是“remote login”(远程登陆)的缩写。该命令与telnet命令很类似,容许用户启动远程系统上的交互命令会话。
rlogin 的通常格式是:
rlogin [ -8EKLdx ] [ -e char ] [-k realm ] [ - l username ] host
通常最经常使用的格式是:
rlogin host
该命令中各选项的含义为:
-8 此选项始终容许8位输入数据通道。该选项容许发送格式化的ANSI字符和其余的特殊代码。若是不用这个选项,除非远端的终止和启动字符不是或,不然就去掉奇偶校验位。
-E 中止把任何字符看成转义字符。当和-8选项一块儿使用时,它提供一个彻底的透明链接。
-K 关闭全部的Kerberos确认。只有与使用Kerberos 确认协议的主机链接时才使用这个选项。
-L 容许rlogin会话在litout模式中运行。要了解更多信息,请查阅tty联机帮助。
-d 打开与远程主机进行通讯的TCP sockets的socket调试。要了解更多信息,请查阅setsockopt的联机帮助。
-e 为rlogin会话设置转义字符,默认的转义字符是“~”,用户能够指定一个文字字符或一个\\nnn形式的八进制数。
-k 请求rlogin得到在指定区域内的远程主机的Kerberos许可,而不是得到由krb_realmofhost(3)肯定的远程主机区域内的远程主机的Kerberos 许可。
-x 为全部经过rlogin会话传送的数据打开DES加密。这会影响响应时间和CPU利用率,可是能够提升安全性。
4.rsh命令
rsh是“remote shell”(远程 shell)的缩写。 该命令在指定的远程主机上启动一个shell并执行用户在rsh命令行中指定的命令。若是用户没有给出要执行的命令,rsh就用rlogin命令使用户登陆到远程机上。
rsh命令的通常格式是:
rsh [-Kdnx] [-k realm] [-l username] host [command]
通常经常使用的格式是:
rsh host [command ]
command能够是从shell提示符下键人的任何Linux命令。
rsh命令中各选项的含义以下:
-K 关闭全部的Kerbero确认。该选项只在与使用Kerbero确认的主机链接时才使用。
-d 打开与远程主机进行通讯的TCP sockets的socket调试。要了解更多的信息,请查阅setsockopt的联机帮助。
-k 请求rsh得到在指定区域内的远程主机的Kerberos许可,而不是得到由krb_relmofhost(3)肯定的远程主机区域内的远程主机的Kerberos许可。
-l 缺省状况下,远程用户名与本地用户名相同。本选项容许指定远程用户名,若是指定了远程用户名,则使用Kerberos 确认,与在rlogin命令中同样。
-n 重定向来自特殊设备/dev/null的输入。
-x 为传送的全部数据打开DES加密。这会影响响应时间和CPU利用率,可是能够提升安全性。
Linux把标准输入放入rsh命令中,并把它拷贝到要远程执行的命令的标准输入中。它把远程命令的标准输出拷贝到rsh的标准输出中。它还把远程标准错误拷贝到本地标准错误文件中。任何退出、停止和中断信号都被送到远程命令中。当远程命令终止了,rsh也就终止了。
5.rcp命令
rcp表明“remote file copy”(远程文件拷贝)。该命令用于在计算机之间拷贝文件。
rcp命令有两种格式。第一种格式用于文件到文件的拷贝;第二种格式用于把文件或目录拷贝到另外一个目录中。
rcp命令的通常格式是:
rcp [-px] [-k realm] file1 file2 rcp [-px] [-r] [-k realm] file
directory 每一个文件或目录参数既能够是远程文件名也能够是本地文件名。远程文件名具备以下形式:rname@rhost:path,其中rname是远程用户名,rhost是远程计算机名,path是这个文件的路径。
rcp命令的各选项含义以下:
-r 递归地把源目录中的全部内容拷贝到目的目录中。要使用这个选项,目的必须是一个目录。
-p 试图保留源文件的修改时间和模式,忽略umask。
-k 请求rcp得到在指定区域内的远程主机的Kerberos 许可,而不是得到由krb_relmofhost(3)肯定的远程主机区域内的远程主机的Kerberos许可。
-x 为传送的全部数据打开DES加密。这会影响响应时间和CPU利用率,可是能够提升安全性。 若是在文件名中指定的路径不是完整的路径名,那么这个路径被解释为相对远程机上同名用户的主目录。若是没有给出远程用户名,就使用当前用户名。若是远程机上的路径包含特殊shell字符,须要用反斜线(\\)、双引号(”)或单引号(’)括起来,使全部的shell元字符都能被远程地解释。 须要说明的是,rcp不提示输入口令,它经过rsh命令来执行拷贝。
l 取消命令
在vi中,只要没有把修改结果存入磁盘文件中,那么就能够经过“取消”来撤销最近的操做或对缓冲区的修改。
假设你无心删除了一行文本、改变了一些你不该该改变的内容或增长了一些不正确的文本,能够按<Esc>改变到命令模式中,而后按<u>,则文件内容恢复到修改前的样子。
l 保存到文件名为filename的文件中
发出写命令格式: :w filename
l 不使用小键盘来定位光标
vi用<h>、<j>、<k>、<l>键来定位光标。其中<h>、<l>键表示光标的左右移动,<j>、<k>键表示光标的上下移动,在某些没有或不能使用小键盘的状况下这四个键是颇有用的。
下面是其余一些用于移动光标的键:
n 按空格键或<l>向右移动光标一个位置
n 按<Return>将光标移动到下一行的行首
n 使用<j>键将光标移动到下一行的当前位置或行末
n 按<->将光标移动到上一行行首
n 使用<k>键将光标移动到上一行的当前位置或行末
n 按<h>将光标向左移动一个字符
n 按<0>(零)将光标移动到一行的行首
n 按<$>将光标移动到一行的行末
l 大范围移动键
可快速定位光标到屏幕的顶部、中部和底部:
n 按<Shift-h>将光标移到屏幕的第一行,有时称为home位置
n 按<Shift-m>将光标移到如今屏幕显示的各行的中间一行
n 按<Shift-l>将光标移到屏幕的最后一行
n 按<Ctrl-f>向前移动一屏
n 按<Ctrl-b>向后移动一屏
n 要移动到缓冲区中指定的行中,在按<Shift-g>前键入行号(注意,这里的行号不是当前屏幕中的相对行号,而是绝对行号)
l 删除文本
n <x>删除光标处的字符
n <d> <w> 删除从当前字的光标处到下一个字的开始处之间的内容
n <d> <$> 删除从光标处到行尾之间的内容
n <Shift-d> 同<d> <$>,删除当前行的剩余部分
n <d> <d> 删除整行,无论光标在该行的位置
n 经过在上述命令以前键入一个整数,可将这些命令应用到几个对象中,例如:<4> <x>删除4个字符;<8> <d> <d> 删除8行
l 添加文本
n 使用<i>在光标位置前插入文本
n 使用<Shift-i>使你进入输入模式而且在当前行行首插入文本
n 使用<a>在光标位置后插入文本
n 使用<Shift-a>使你进入输入模式而且在当前行末尾插入文本
n 使用<o>在当前行的下面打开一行以添加文本
n 使用<Shift-o>在当前行的上面打开一行以添加文本
l 使vi显示行号
按<Esc>键以确保你在命令模式中,而后输入:se number。要关闭行号,输入:se nonumber
l 查找
n /string 在缓冲区中向前查找字符串string
n ?string 在缓冲区中向后查找字符串string
n <n> 以当前的方向再次查找
n <Shift-n>以相反的方向再次查找
n 注意,查找的字符串中若含有特殊字符的,要使用\来进行转意
l 修改和替换文本
n <r> 替换单个字符
n <Shift-r>替换一个字符序列
n <c> <w>修改当前字,从光标处到这个字的字尾
n <c> <e>修改当前字,从光标处到这个字的字尾(与<c> <w>相同)
n <c> <b>修改当前字,从该字的字头到光标之前的那些字符
n <c> <$>修改一行,从光标处到该行的行尾
n <Shift-c>修改一行,从光标处到该行的行尾(与<c> <$>相同)
n <c> <c>修改整行
n 注意,这些命令的每一个命令都使之进入了输入模式。除使用<r>来替换单个字符外,必须按<Esc>键来完成所做的修改并返回命令模式
n 要修改几个字,在按<c> <w>以前使用一个整数
l 拷贝、剪切和粘贴
n <y> <w>拷贝从当前字的光标处到下一个字的开始处之间的内容
n <y> <$>拷贝从光标处到行尾之间的内容
n <Shift-y>拷贝当前行的剩余部分(与<y> <$>相同)
n <y> <y>拷贝整个当前行
n 经过在这些命令前键入整数,全部这些命令均可以用于多个对象。
n 当删除或剪切或拷贝时,删除或拷贝的对象被保存在通用缓冲区中,能够使用<p>或<Shift-p>命令将这个缓冲区中的内容粘贴到光标位置。
n <p>命令将对象粘贴到光标位置右边或光标位置后面
n <Shift-p>命令将对象粘贴到光标位置左边或光标位置前面
l 重复命令
能够按< . >来重复改变缓冲区的最后一个命令。