1、环境变量
(1)环境变量分为全局环境变量和局部环境变量。
系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。用户定义的局部变量建议使用小写字母。
使用环境变量时,需要在变量前面加 $。操作环境变量时,不使用$。(注:$HOME 等同于 ~,表示某个用户的主目录。)
显示某个特定进程设置的所有环境变量:set
设置局部环境变量:(1)echo $my_variable,(2)赋值:my_variable=Hello 或者 my_variable="hello world"。注意:变量名、等号和值之间没有空格。
向变量中存储的已有文本字符串尾部添加文本的常用方法:
variable="Alabama Alaska Arizona" variable=$variable" Connecticut"
设置全局环境变量:(1)echo $my_variable,(2)赋值:同上,(3)export my_variable。
变量之间赋值:my_variable=$other_variable
删除环境变量:unset my_variable。
当前的PID:$$
(2)数组变量
给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔。
格式:my_variable=(one two three four five ......)
引用数组中的某个元素:${my_variable[n]};#索引值n从0开始。
显示整个数组变量:${my_variable[*]}
改变某个索引值的位置:my_variable[n]=10
删除数组中的某个值:unset my_variable[n];注意:删除后,后面的元素还是保持在原有位置,被删除的位置还存在,只不过值为空。
删除整个数组:unset my_variable
2、文件权限
(1)使用文件权限符:
-:代表文件 d:代表目录 l:代表链接 c:代表字符型设备 b:代表块设备 n:代表网络设备
之后有3组三字符的编码,每一组定义了3种访问权限:r代表对象是可读的,w代表对象是可写的,x代表对象是可执行的。如果没有某种权限,在该权限位会出现单破折线。
3组权限分别对应对象的3个安全级别:对象的属主、对象的属组、系统的其他用户。
三字符对应存在一个八进制值,例如:rwx:7,rw-r--r--:644
(2)显示和设置默认权限:umask
文件的原始权限为:666,即所有用户都有读和写的权限。
目录的原始权限为:777,即所有用户都有读、写和可执行。
为什么上面图片中-rw-r--r--的八进制表示为644?因为该系统具有默认权限022,因此剩下的文件权限为644=666-022。
注意:umask命令显示得到的默认权限其实有4位,即0022,第一位是用于共享文件中的安全特性,具体细查。
3、vim编辑器
(1)普通模式下,vim编辑器提供了一些命令来编辑缓冲区中的数据。
删除当前光标所在位置的n个字符:(n)x 删除当前光标所在位置的n行:(n)dd 删除当前光标所在位置的n个单词:(n)dw
删除当前光标所在位置至行尾的内容:d$ 删除当前光标所在行行尾的换行符(拼接行):J
撤销前一编辑命令:u 在当前光标后追加数据:a 在当前光标所在行行尾追加数据:A
用char替换当前光标所在位置的单个字符:r char 用text覆盖当前光标所在位置的数据,直到按下ESC键:R text
复制当前光标所在位置的n行:(n)yy 复制当前光标所在位置的n个单词:(n)yw 复制当前光标所在位置至行尾的内容:y$
复制第26行至50行:命令模式下,:26,50y
粘贴:p
查找:/查找的文本 向下查找:n 向上查找:N
替换当前行的old为new::s/old/new 替换当前行所有old为new::s/old/new/g
替换第n行开始到最后一行中每一行的第一个old为new::n,$s/old/new/
替换第n行开始到最后一行中每一行所有的old为new::n,$s/old/new/g
替换整个文件中的所有old::%s/old/new/g 替换整个文件中的所有old,但在每次出现时提示::%s/old/new/gc
4、shell脚本文件
(1)脚本文件:第一行为:#!/bin/bash(!表示告诉shell用哪个shell来运行脚本。)
脚本文件test:
#!/bin/bash
echo this is a test file.
date
运行脚本文件:(1)test;一般会报错bash: test: command not found。此时可以将shell脚本文件所处的目录添加到PATH环境变量中;(2)./test;使用绝对或相对文件路径来引用shell脚本文件。
(2)命令替换:从命令输出中提取信息,并将其赋给变量。
将命令输出赋给变量:反引号字符(··)和$()。
例:variable_output=`date` 或 variable_output=$(date)
(3)重定向输入和输出
例如:command > outputfile 或 command >> outputfile
输出重定向 > :将命令的输出发送到一个文件中,如果该文件已有内容,则会被覆盖。
输出重定向并追加内容>>:将命令的输出发送到一个文件中,如果该文件已有内容,则会追加到之前内容后面。
例如:command < inputfile
输入重定向 <:将文件的内容重定向到命令。
例如:command << marker
data
marker
内联输入重定向 <<:必须指定一个文本标记marker来划分输入数据的开始和结尾。任何字符串都可以作为文本标记,但在数据的开始和结尾文本标记必须一致。
(4)管道
例如:command1 | command2 | command3
管道连接 | :将一个命令的输出作为另一个命令的输入。
注意:由管道串起来的命令会同时运行,在系统内部将他们连接起来,在第一个命令产生输出的同时,该输出会被立即送给第二个命令。
(5)执行数学运算
例如:expr 1 \< 5
用来在命令行上处理数学表达式:expr
由于使用expr执行数学运算时,要在运算符前加转义操作符 \,所以不是很方便。
(6)使用方括号
为了解决这个问题,bash shell提供了一种简单的方法来执行数学表达式:使用方括号。
使用方括号能够将一个数学运算结果赋给某个变量:my_variable=$[40 - 20]。
注意:使用方括号不需要在运算符前加转义符号。但是也存在一个问题,即:只支持整数运算(例如:100/45=2)
(7)浮点解决方案
bash计算器:bc(本版本linux中没有,所以用时具体细查。。。)
5、退出脚本
(1)退出状态码
shell中运行的每个命令都使用退出状态码(0-255的整数值)来表明命令结束。
显示上一命令结束后返回的状态码:echo $?
命令成功结束的退出状态码值:0 没找到命令:127
(2)exit命令
exit命令允许在脚本结束时指定一个退出状态码。即:在脚本文件最后一行写入:exit 状态码值。
注意:当返回的退出状态码值超出区间,shell通过对256取模运算后的值作为退出状态码值。
6、结构化命令
(1)使用 if-then语句
格式:
if command 或者 if command; then
then commands
commands fi
fi
解释:当if语句运行后面的那个命令的退出状态码为0时,位于then部分的命令就会被执行,如果状态码为其他值,则then部分的命令就不会被执行。
(2)使用 if-then-else 语句
格式:
if command
then
commands
else
commands
fi
解释:当 if 语句中的命令返回退出状态码0时,then部分中的命令会被执行;当 if 语句中的命令返回非零退出状态码时,else部分中的命令会被执行。
(3)嵌套 if
格式:
if command
then
commands
elif command
then
commands
else
commands
fi
(4)test命令
if-then 语句不能测试命令退出状态码之外的条件,因此bash shell提供test命令在if-then 语句中测试不同条件的途径。如果test命令中列出的条件成立,test命令就会退出并返回退出状态码0。
格式:
if test condition
then
commands
fi
如果 test 命令不加condition部分,它会以非零状态码退出,并执行else语句块。
另外一种测试方法:
if [ condition ] #注意:第一个方括号之后和第二个方括号之前必须加上一个空格。
then
commands
fi
test命令可以判断三类条件:(具体可以细查)
a、数值比较 b、字符串比较 c、文件比较
(5)复合条件测试
if-then 语句中使用布尔逻辑组合测试。两种布尔运算符可用:
(a)[ condition1 ] && [ condition2 ] # 与:两个比较都必须满足才会执行if的then部分
(b)[ condition1 ] || [ condition2 ] # 或:两个比较只需要满足一个以上就会执行if的then部分
(6)if-then 的高级特性
(a)用于数学表达式的双括号
双括号允许在比较过程中使用比 test 命令更高级的数学表达式。格式:(( expression ))
if (( expression ))
then
commands
fi
(b)双方括号——针对字符串比较的高级特性
双方括号中 expression 使用了test命令中采用的标准字符串比较,但它提供了 test 命令未提供的一个特性——模式匹配。
格式:[[ expression ]]
if [[ expression ]]
then
commands
fi
(7)case命令
格式:
case variable in
pattern1 | pattern2) commands1;; # 满足pattern1或pattern2,则执行 commands1
pattern3) commands2;; # 满足pattern3,则执行commands2
*) default commands;; # 都不满足,则执行commands
esac
当在一组可能的值中寻找特定的值时,不得不写出很长的 if-then-else语句,例如
if [[ $USER == "admin0" ]] 改为: case $USER in
then admin0) echo......;;
echo...... admin1) echo......;;
elif [[ $USER == "admin1" ]] *) echo......;;
then esac
echo...... 注意:千万别忘记两个分号 ;;
else
echo......
fi
7、更多的结构化命令
(1)for 命令
格式: 例如:
for var in list for word in I don\'t know if this\'ll work # 注意:list的形式
do do
commands echo "word: word"
done done
(a)使用转义字符(反斜线)将单引号转义;如上例。
(b)使用双引号("")定义用到单引号的值;如:" don't "
for 循环假定每个值都是用空格分割的。如何处理自带空格的数据值(如:United states)?正确做法:用双引号将这些值圈起来。注意:在某个值两边使用双引号时,shell不会将双引号当做值的一部分。如果想当做值的一部分,则需要加转义字符。
(c)更改内部字段分隔符IFS:空格、制表符和换行符
当列表中出现以上字符中的任何一个字符,bash shell都将认为是一个新数据字段的开始。
例子:
文件名带有空格的文件:a b.txt
shell脚本文件:
#!/bin/bash
file="a b.txt"
for state in $(cat $file) #注意:这里会把变量file认为是一个list,而不是一个文件
do
echo......
done
要解决例子中的问题,做法:在shell脚本文件中临时更改IFS环境变量的值来限制被bash shell当做字段分隔符的字符。
IFS=$'\n';这个语句能告诉bash shell在数据值中忽略空格和制表符。
如果只是在脚本文件的部分地方需要修改IFS值,则可以按如下操作:
IFS.OLD=$IFS
IFS=$'\n'
<在代码中使用新的IFS的值>
IFS=$IFS.OLD
如果要指定多个IFS字符,则只要将它们在赋值行串起来就行:IFS=$'\n':;"
(2)shell中C语言的for命令
格式:for (( variable assignment ; condition ; iteration process ))
(a)变量赋值可以有空格; (b)条件中的变量不以美元符开头; (c)迭代过程的算式未使用expr命令格式
注意:可以在for循环中定义多个变量,但是condition只能有一种。
(3)while命令
格式:
while test command # 每轮迭代都要执行测试命令,所以关键在于如何使得退出状态码发生改变,使得退出循环体。
do
commands # 为了避免陷入死循环,在循环体中必须要修改测试条件中用到的变量。
done
while中可以使用多个测试命令,每个测试命令都出现在单独的一行上,如下:
while test command
test command
do
commands
done
(4)until命令
和while命令工作方式相反,until命令指定一个通常返回非零退出状态码的测试命令,当退出状态码为0时,until命令会退出循环体,循环结束。格式如下:
until test command
test command
do
commands
done
注意:until命令中使用多个测试命令时,只有最后一个命令的退出状态码决定了是否决定执行循环体。
(5)控制循环
(a)break命令
在内部循环中,需要停止外部循环:break n;其中 n 指定了要跳出的循环层级,默认情况下,n为1,表示退出当前循环。
(b)continue命令
与 break 命令类似,continue 命令也允许通过命令行参数指定要继续执行哪一级循环:continue n
(6)处理循环的输出
在shell脚本中,可以对循环的输出使用 管道 或进行重定向。这可以在done命令之后添加一个处理命令来实现,这将使得循环的输出不会显示在屏幕上。
8、处理用户输入
(1)命令行参数
位置参数: 程序名 $0 第一个参数 $1 第二个参数 $2 依次下去,直到第9个参数$9
第十个参数 ${10} 第十一个参数 ${11} 以此类推。。。。。。
问题:当使用 $0 获取脚本名时,使用 ./ 运行脚本会使得得到的脚本名中混有命令 ./,另外,当传给$0变量的实际字符串不仅仅是脚本名,而是完整的脚本路径时,变量$0就会使用整个路径。这个问题可以使用命令 basename 解决,它返回不包含路径的脚本名。
注意:不能再 {} 里使用$,具体原因可以看看${$#}的值。
(2)特殊参数变量
(a)参数统计
用于统计命令行中输入参数的个数:$#
最后一个命令行参数变量:${!#}
注意:当命令行中没有任何参数时,$#的值为0,但${!#}变量会返回命令行用到的脚本名。
(b)抓取所有的数据
$* 和 $@这两个变量都能够在单个变量中存储所有的命令行参数。
$*:将命令行上提供的所有参数当做一个单词保存,将这些参数视为一个整体,而不是多个个体。
$@:将命令行上提供的所有参数当做同一个字符串中的多个独立的单词,能用for循环进行遍历。
两者区别:
文件test.sh的内容: 文件test1.sh的内容
#!/bin/bash #!/bin/bash
# testing $* and $@ # testing $* and $@
echo "Using the \$* method: $*" echo "Using the \$* method: $*"
echo "Using the \$@ method: $@" echo "Using the \$@ method: $@"
count=1 count=1
for param in "$*" for param in $*
do do
echo "\$* Parameter #$count = $param" echo "\$* Parameter #$count = $param"
count=$[ $count+1 ] count=$[ $count+1 ]
done done
# #
count=1 count=1
for param in "$@" for param in $@
do do
echo "\$@ Parameter #$count = $param" echo "\$@ Parameter #$count = $param"
count=$[ $count+1 ] count=$[ $count+1 ]
done done
结果
(c)移动变量
shift:操作命令行参数。根据它们的相对位置来移动命令行参数,默认情况下它会将每个参数变量向左移动一个位置,即变量$3的值会移动到$2中,变量$2的值会移动到$1中,而变量$1的值会被删除(注意:变量$0的值,即程序名不会改变。)
一次性移动多个位置:shift n
(d)处理选项
选项:跟在命令后面的带有单破折线的字母。
使用case和shift来处理简单的选项。
区分参数和选项(选项在前,参数在后):shell会用双破折线(--)来表明选项列表结束。在双破折线之后,shell脚本将剩下的命令行参数当做参数处理。
处理带值的选项:在case中进行处理,即$1为选项,则$2为参数值。
处理任意形式的命令行选项和参数的命令:getopt(或getopts)
格式:getopt optstring parameters
注:optstring定义了命令行有效的选项字母,和哪些选项字母需要参数值。列出脚本中用到的每个命令行选项字母,在每个需要参数值的选项字母后加一个冒号。
(3)获得用户输入
(a)基本的读取
从标准输入或另一个文件描述符中接受输入:read my_variable 注:会将输入的所有数据分配给单个变量,或者假如指定多个变量,输入的每个数据值都会分配给变量列表中的下一变量,如果变量数量不够,剩下的数据就全部分配给最后一个变量。
(b)隐藏方式读取
将输入的数据不出现在显示器上:read -s my_variable 注:类似于输入密码,但要注意其实数据会被显示,只是数据颜色跟背景色一样。
(c)从文件读取
read命令会从文件中读取一行文本,当文件中再没有内容时,read命令会退出并返回非零退出状态码。
将文件中的数据传给read命令:cat filename | while read my_variable
9、呈现数据
(1)标准文件描述符
linux系统用文件描述符来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开的文件。每个进程一次最多可以有9个文件描述符。bash shell保留了前三个文件描述符0、1、2,分别表示标准输入STDIN、标准输出STDOUT、标准错误STDERR。
注意:其实文件描述符可以理解为就是一个对象的别名,在脚本命令行中利用这个别名对对象进行操作,这样的话就不需要直接操作具体的对象了。例如:在脚本中重定向输出中的永久重定向,先利用exec命令指定文件描述符1代表指定的文件testout,然后command ... >&1表示command ... > testout。(如果理解有误,请批评指正。)
(2)重定向错误
默认情况下,STDERR文件描述符会和STDOUT文件描述符指向同样的地方,即:输出到显示器输出中。
(a)只重定向错误
将STDERR错误消息重定向输出到文件中:2> filename
(b)重定向错误和数据
将STDERR错误消息和STDOUT数据分别重定向到对应的文件中:1> OutputFilename 2> ErrorFilename
将STDERR错误信息和STDOUT数据重定向到同一个输出文件:&>
(3)在脚本中重定向输出
(a)临时重定向
运行脚本文件时,默认情况下会将所有输出信息定向到STDOUT文件描述符,为了将数据信息输出到显示器输出中,而错误信息则输出到指定的文件中。此时,可以将单独的一行输出重定向到STDERR,在重定向到文件描述符时,必须在文件描述符数字之前加一个&:command ... >&2,然后在运行脚本时,指定导向STDERR的文本重定向到对应的文件:./filename 2> errorfilename
(b)永久重定向
如果脚本中有大量数据需要重定向,那么使用临时重定向的方法很麻烦。可以使用exec命令告诉shell在脚本执行期间重定向到某个特定文件描述符。exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。
exec 1>testout;该命令表示将信息输出到STDOUT改为输出到文件testout中。
command ... >&1;这行的信息输出到testout文件中。
(4)在脚本中重定向输入
exec命令还能够将STDIN重定向到Linux系统上的文件中:exec 0< testfile。这个命令告诉shell应该从文件testfile中获得输入,而不是STDIN。
(5)创建自己的重定向
在脚本文件中重定向输入和输出时,不局限于STDIN、STDOUT和STDERR这3个默认的文件描述符。其他6个3-8的文件描述符均可用作输入或输出重定向。
(a)创建读写文件描述符
exec 3<> testfile;表示将文件描述符3分配给文件testfile以进行读写文件。不过这种方法要小心,对同一文件进行数据读写时,shell会维护一个内部指针,指明在文件中的当前位置。任何读或写都会从文件指针上次的位置开始,所以在写的时候会将原有位置的数据进行覆盖。
(b)关闭文件描述符
格式:exec 3>&-;该语句会关闭文件描述符3,不再脚本中使用。
(c)列出打开的文件描述符
命令:lsof
(d)阻止命令输出
为了解决脚本运行时会生成很多的小错误这个问题,可以将STDERR重定向到一个叫做null文件的特殊文件。null文件表示什么都没有,shell输出到null文件的任何数据都不会保存,全部被丢掉,不会显示。
另外,可以在输入重定向中将/dev/null作为输入文件,通常用它来快速清除现有文件中的数据,而不用先删除文件再重新创建。
(6)创建临时文件
linux系统使用/tmp目录来存放不需要永久保留的文件。大多数linux发行版配置了系统在启动时自动删除/tmp目录的所有文件。
mktemp命令可以在/tmp目录中创建一个唯一的临时文件,它会将文件的读和写权限分配给文件的属主。
(a)创建本地临时文件
用mktemp命令在本地目录中创建一个临时文件,只要指定一个文件名模板就行,模板可以包含任意文本文件名,在文件名末尾加上6个X就行了。mktemp命令会用6个字符码替换6个X,从而保证文件名在目录中是唯一的。
格式:mktemp filename.XXXXXX
(b)在/tmp目录中创建临时文件
-t选项会强制mktemp命令在系统的临时目录来创建该文件,返回用来创建临时文件的全路径,而不是只有文件名。
(c)创建临时目录
-d选项会让mktemp命令创建一个临时目录而不是临时文件。
(d)记录消息
不需要将输出重定向两次,就能将输出同时发送到显示器和日志文件,使用tee命令。
tee命令相当于管道的一个T型接头,将从STDIN过来的数据同时发往两处,一处是STDOUT,另一处是tee命令行所指定的文件名:tee filename。tee命令会在每次使用时覆盖输出文件内容,若想将数据追加到文件中,使用-a选项。
10、创建函数
(1)创建函数
格式1:采用关键字function 格式2:
function name { name() {
commands commands
} }
(2)返回值
bash shell会将函数作为一个小型脚本,运行结束时会返回一个退出状态码,有3种不同的方法来为函数生成退出状态码。
(a)默认退出状态码
默认情况下,函数的退出状态码是最后一条命令返回的退出状态码。可以用标准变量$?来确定函数的退出状态码。但是,需要谨慎使用,因为退出状态码为0不一定是函数成功执行(退出状态码只看脚本文件中最后一条命令是否执行成功)。
(b)使用return命令
使用 return 命令来退出函数并返回特定的退出状态码。return 命令允许指定一个整数值来定义函数的退出状态码,从而来设定函数退出状态码。
利用这种方法从函数中返回值时,要记住下面两条技巧来避免问题:
1、函数一结束就取返回值(利用特殊变量 $? 获取函数return命令的值);
2、退出状态码必须是0-255,任何大于255的值都会产生一个错误值。
(c)使用函数输出
将函数的输出保存到shell变量中。格式:my_variable=$(functionname) 或 my_variable=`functionname`
(3)在函数中使用变量
(a)向函数传递参数
可以使用标准的参数环境变量来表示命令行上传给函数的参数,例如:$1、$2等等。
在脚本中指定函数时,必须将参数和函数放在同一行,格式:functionname $1 20
(b)在函数中处理变量
函数中定义的变量与普通变量的作用域不同,对脚本其他部分而言,它们是隐藏的。函数使用两种类型的变量:全局变量和局部变量。
1、全局变量:在shell脚本中任何地方都有效的变量。
2、局部变量:函数内部使用的任何变量都可以被声明为局部变量:local temp。local关键字保证了变量只局限在该函数中。如果在函数之外有同样名字的变量,那么shell将会保持这两个变量的值是分离的。
(4)数组变量和函数
(a)向函数传递数组参数
如果将数组变量作为函数参数,函数只会取数组变量的第一个值。要解决这个问题,必须将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。
格式:functionname ${my_variable[*]};在函数中利用自定义变量variable=('echo "$@"')或者variable=($(echo "$@"))。
(b)从函数返回数组
函数用echo语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。
(5)在命令行上使用函数
(a)在命令行上创建函数
可以在命令行上直接定义一个函数,有两种方法:
1、采用单行方式定义函数
function functionname { command1;command2;......; }
2、采用多行方式来定义函数
function functionname {
command1
command2
}
注意:在命令行上创建函数时,要避免跟内建命令或另一个命令相同的名字,函数将会覆盖原来的命令。
11、初识sed和gawk
sed和gawk工具用来处理任何类型的数据。
(1)文本处理
(a)sed编辑器——流编辑器
交互式文本编辑器可以用键盘命令来交互式地插入、删除或替换数据中的文本,而流编辑器则会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流,符合规则的数据位于模式空间中。sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本文件中。sed编辑器会执行下列操作:
1、一次从输入中读取一行数据;
2、根据所提供的编辑器命令匹配数据;
3、按照命令修改流中的数据;
4、将新的数据输出到STDOUT,然后重复步骤1,直到结束。 注意:不会修改原始文本文件的数据。
格式:sed options script file
a)在命令行定义编辑器命令
默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。例如:使用s命令用斜线间指定的第二个文本字符串来替换第一个文本字符串模式:echo "This is a test" | sed 's/test/big test/' 注意:默认情况下,s命令只替换每行中出现的第一处。
b)在命令行使用多个编辑器命令
用-e选项就行:sed -e 's/test/big test/;s/test/small test/' 注意:命令之间用分号;隔开,并且命令末尾和分号之间不能有空格。
或者利用bash shell中的次提示符来分隔命令。只要输入第一个单引号标示出sed程序脚本的起始,bash会提示输入更多的命令,直到输入了标示结束的单引号。
例如:
echo "This is a test" | sed -e '
s/test/big test/
s/test/small test/
'
c)从文件中读取编辑器命令
如果有大量要处理的sed命令,可以将它们放入一个单独的文件中。用 -f 选项来指定文件。
格式:sed -f script.sed data.txt 注意:使用.sed作为sed脚本文件的扩展名。
(b)更多的替换选项
1)替换标记
格式:s/pattern/replacement/flags
有4种可用的替换标记:
数字n:表明新文本replacement将替换每行中第 n 处出现模式匹配的地方; g:表明新文本将会替换所有匹配的文本;
p:表明原先行的内容要打印出来(通常与-n结合使用); w file:将替换的结果写到文件中。
2)替换字符
文本字符串中会出现一些不方便在替换模式中使用的字符,比如路径中存在正斜线 / ,这和替换格式中冲突,虽然可以用转义字符反斜线处理,但是另外一种方法是使用 !,即:s!pattern!replacement!
(c)使用地址
sed编辑器使用 行寻址 来将命令作用于特定行或某些行。sed编辑器中有两种形式的行寻址:
以数字形式表示行区间;用文本模式来过滤出行。
格式:指定地址 将特定地址的多个命令分组:address {
[address] command command1
command2
}
sed编辑器会将指定的每条命令作用到匹配指定地址的行上。
1)数字方式寻址
sed编辑器会将文本流中的第一行编号为1,然后继续按顺序为接下来的行分配行号。使用数字方式的行寻址,可以用行在文本流中的行位置来引用。
在命令中指定的地址可以是单个行号,或是起始行号、逗号以及结尾行号指定的一定区间范围内的行。
作用于第n行:sed 'ns/pattern/replacement/flags'
作用于第n1行到第n2行:sed 'n1,n2s/pattern/replacement/flags'
作用于从第n行开始的所有行:sed 'n,$s/pattern/replacement/flags'
2)使用文本模式过滤器
在s命令前面加入一个正则表达式pattern来过滤:格式:/pattern/s/pattern/replacement/flags
3)命令组合
结合次提示符,用花括号{}将多条命令组合在一起。
sed 'n1,n2{
s/pattern/replacement/flags
s/pattern/replacement/flags
}' filename
(d)删除行
sed编辑器能够删除文本流中的特定行。删除命令d会删除匹配指定寻址模式的所有行。注意:未加寻址模式,会删除所有行。
格式1:sed 'n1,n2d' filename 或者 sed '/n1/,/n2/d' filename # 删除第n1行到第n2行。
格式2:sed '/pattern/d' filename
注意:使用pattern模式时,指定的第一个模式会 “打开”行删除功能,第二个模式会 “关闭”行删除功能,因此,需特别小心文本数据中同时出现多个与第一个模式匹配的数据,否则的话,将会删除全部匹配的数据。
(e)插入和附加文本
插入命令(i)会在指定行前增加一个新行;
附加命令(a)会在指定行后增加一个新行。
格式: 例如:在第3行前插入一行
sed '[address]command\ sed '3i\
new line\ this is new line.' filename
new line' filename
其中,new line中的文本将会出现在sed编辑器输出中指定的位置。
(f)修改行
修改命令(c)允许修改数据流中整行文本的内容。
格式: 例如:修改第3行中的文本
sed '[address]command\ sed '3c\
new line\ this is new line.' filename
new line' filename
也可以用文本模式来寻址:
sed '/pattern/c\
new line' filename
如果修改命令中使用地址区间,会将该区间内的所有文本变成new line。
(g)转换命令
转换命令(y)是唯一可以处理单个字符的sed编辑命令。格式:
sed '[address]y/inchars/outchars/' filename
转换命令会对inchars和outchars值进行一对一的映射。inchars中的第n个字符会被转换为outchars中的第n个字符。如果inchars和outchars的长度不同,则sed编辑器会产生一条错误消息。
(h)打印
用来打印数据流中信息的3个命令:
p命令用来打印文本行; 等号(=)命令用来打印行号; l(小写的L)命令用来列出行。
1)打印行
类似替换命令中的p标记,p命令可以打印sed编辑器输出中的一行。
打印第n1行到第n2行的所有文本数据:sed -n 'n1,n2p' filename 或 sed -n '/pattern/p' filename
2)打印行号
等号命令会打印行在数据流中的当前行号。行号由数据流中的换行符决定。每次数据流中出现一个换行符,sed编辑器会认为一行文本结束了。
显示含匹配文本模式的行的行号和文本:sed -n '/pattern/=' filename
(I)列出行
列出命令(l)可以打印数据流中的文本和不可打印的ASCII字符。
(J)写入文件
写入命令w用来向文件写入行
格式:将filename2中寻址的数据流写入到filename1中
sed '[address]w filename1' filename2
(K)从文件读取数据
读取命令 r 用来将独立文件中的数据插入到数据流中。
格式:将filename1中的数据插入到filename2指定的寻址位置后
sed '[address]r filename1' filename2
(2)sed进阶
(a)多行命令
前面都是利用sed编辑器针对单行数据执行的操作,针对多行文本数据操作,可以有3个命令:
N:将数据流中的下一行加进来创建一个多行组来处理;
D:删除多行组中的一行;
P:打印多行组中的一行。
(1)单行的 next 命令
小写的 n 命令会告诉sed编辑器移动到数据流中的下一文本行,而不用重新回到命令的最开始再执行一遍。
删除filename中与pattern匹配的文本行的下一行:sed '/pattern/{n;d}' filename
(2)合并文本行
多行版本的next命令(大写的N)会将下一文本行添加到模式空间中已有的文本后。但是文本行仍然用换行符分割,不过sed编辑器会将两行文本当成一行来处理。
将filename中与pattern匹配的文本行的下一行合并到同一行中,并用空格符替换换行符:sed '/pattern/{N;s/\n/ /}' filename
(3)多行删除命令
多行删除命令(D),只会删除模式空间中的第一行,该命令会删除到换行符(含换行符)为止的所有字符。和N命令结合使用。
(4)多行打印命令
多行打印命令(P),只会打印模式空间中的第一行,该命令会打印到换行符(含换行符)为止的所有字符。
P命令一般和N命令、D命令结合使用。
(b)保持空间
模式空间是一块缓冲区,保持空间也是一块缓冲区,在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。有5条命令可用来操作保持空间:
h:将模式空间复制到保持空间 H:将模式空间附加到保持空间 g:将保持空间复制到模式空间
G:将保持空间附加到模式空间 x:交换模式空间和保持空间的内容
可以利用这种方法将整个文件的文本行反转。
(c)排除命令
感叹号命令(!)用来排除命令,也就是将原本起作用的命令不起作用。
不显示filename中与pattern匹配的文本行:sed -n '/pattern/!p' filename
反转文本步骤:
1)在模式空间中放置一行; 2)将模式空间中的行放到保持空间中; 3)在模式空间中放入下一行;
4)将保持空间附加到模式空间后; 5)将模式空间中的所有内容都放到保持空间中;
6)重复执行第3~5步,直到所有行都反序放到了保持空间中; 7)提取并打印行。
代码:sed -n '{1!G; h; $p}' filename 注意:tac命令也有这个功能
(d)改变流
sed编辑器提供了一个方法来改变命令脚本的执行流程。
(1)分支
利用分支命令(b)可以基于地址、地址模式或地址区间不执行一整块命令,对数据流中的特定行执行一组命令。
格式:[address] b [label]
address参数决定了哪些行的数据会触发分支命令,label参数定义了要跳转到的位置,如果没有加label参数,跳转命令会跳转到脚本的结尾;如果不想跳转到脚本的结尾,可以利用分支命令定义一个要跳转到的标签,标签的格式为(:label2),最多7个字符长度。
例如:sed '{/pattern/b jump1; ......; :jump1;......}' filename # 如果filename文本数据流中文本行与pattern匹配,则直接跳到jump1处继续执行脚本,忽略中间的脚本程序。
(2)测试
测试命令(t)也可以用来改变sed编辑器脚本的执行流程,测试命令会根据替换命令的结果跳转到某个标签,而不是根据地址跳转。
如果替换命令成功匹配并替换了一个模式,测试命令会跳转到指定的标签,否则测试命令就不会跳转。
格式:[address] t [label]
与分支命令类似,在没有指定的label,如果测试成功,会跳转到脚本的结尾。
测试命令提供了对数据流中的文本执行基本的if-then语句。
例如:sed '{s/old/new/;t;......}' filename # 如果filename文本数据流中文本行替换成功,则会跳过 t命令 后面的脚本。
(e)模式替代
使用 s命令 替换数据流中的文本时,每个old和new都很具体,假如old中使用的是通配符来匹配文本,那么如何根据通配符匹配的文本用相应的文本new进行替换?例如:文本数据this is bat and cat. 如果要将bat替换为“bat”,cat替换为“cat”,利用s/.at/".at"/显然无法做到。
(1)&符号
针对上述问题,&符号用来代表替换命令中的匹配的模式,即指定模式的整个字符串。格式:上例中,模式可以写成 s/.at/"&"/
(2)替代单独的单词
sed编辑器用圆括号()来定义替换模式中的子模式,可以在替代模式中使用特殊字符来引用每个子模式。替代字符用 \ 和数字组成,即 \1、\2、。。。,其中数字表明子模式的位置。
例如:echo "That furry cat is pretty" | sed 's/furry \(.at\)/\1/' 结果为:That cat is pretty
(3)创建sed实用工具
(a)加倍行间距
向文本文件的行间插入空白行:sed 'G' filename 注意:该文件末尾是一个空白行。
向文本文件的行间插入空白行,但最后一行不插入:sed '$!G' filename
假如文本文件中已有空白行,如果加倍行间距,会使得某些区域有太多的空白行。解决方法:先删除已有的空白行,然后再插入新的空白行:sed '/^$/d;$!G' filename
(b)给文件中的行编号
可以用等号(=)显示数据流中行的行号,但是行号是在数据流中实际行的上方,如何将行号和文本放在同一行?
解决方法:sed '=' filename | sed 'N;s/\n/ /'
类似的命令:nl cat -n (这两个命令会添加额外的分隔符)
(c)打印末尾行
通过创建滚动窗口,利用美元符来显示数据流末尾的若干行。方法:使用N命令将下一行文本附加到模式空间中已有文本行后面,当达到所需要的文本行数时,用美元符来检查是否处于数据流的尾部,如果不在,就继续向模式空间中增加行,同时删除原来的行。(D命令会删除模式空间中的第一行)
假如文件data.txt有15行,显示最后的10行的方法:sed '{:start; $q; N; 11,$D; b start}' data.txt # 其中q命令为退出。
(d)删除行
选择性删除数据流中不需要的空白行。
(1)删除连续的空白行
删除连续空白行的方法是用地址区间来检查数据流。
例如:删除连续的空白行,只保留一个空白行:sed '/./,/^$/!d' filename
(2)删除开头的空白行
删除数据流顶部的多个空白行:sed '/./,$!d' filename
(3)删除结尾的空白行
删除结尾的多个空白行:sed '{:start; /^\n*$/{$d; N; b start}}' filename
(3)gawk程序
gawk程序是Unix中的原始awk程序的GNU版本(使用ls -al /usr/bin/awk后发现awk是链接到gawk的),nawk是new awk是awk的增强版,增加了很多函数,也可以自己定义函数等。基本用法都差不多。在gawk编程语言中,它提供了一种编程语言而不只是编辑器命令,可以做下面的事情:
1)定义变量来保存数据;
2)使用算术和字符串操作符来处理数据;
3)使用结构化编程的概念(比如if-then语句和循环)来为数据处理增加处理逻辑;
4)通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。
(a)gawk命令格式
gawk命令的强大之处在于程序脚本,可以写脚本来读取文本行的数据,然后处理并显示数据,创建任何类型的输出报告。
格式:gawk options program file
(b)从命令行读取程序脚本
gawk程序脚本用一对花括号来定义。必须将脚本命令放到两个花括号{}中。因为gawk命令行假定脚本是单个文本字符串,必须将脚本放到单引号中。
如果没有给定文件,则gawk程序会从STDIN中获得数据。因此,这种情况下,要终止gawk程序,必须表明数据流已经结束,否则的话,需要使用Ctrl+D组合键来终止。该组合键会在bash中产生一个EOF字符。
(c)使用数据字段变量
gawk程序会自动给一行中的每个数据元素分配一个变量。默认情况下,gawk会将如下变量分配给它在文本行中发现的数据字段:
$0:表示整个文本行 $1:表示文本行中的第1个数据字段
$2:表示文本行中的第2个数据字段 $n:表示文本行中的第n个数据字段
在文本行中,每个数据字段都是通过字段分隔符IFS划分的,默认为空格或制表符。
指定IFS分隔符为 : 的文件处理:gawk -F: '{}' filename
(d)在程序脚本中使用多个命令
要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号即可,例如:gawk '{ .......;......}' filename 。或者直接将花括号中的语句写在次提示符中。
(e)从文件读取程序
gawk也能将程序存储到文件中,然后在命令行中使用。
(f)在处理数据前运行脚本
强制gawk在读取数据前执行BEGIN关键字后指定的程序脚本:gawk 'BEGIN{print "Hello world!"}'
(g)在处理数据后运行脚本
强制gawk在读取数据后执行END关键字指定的程序脚本:gawk 'BEGIN{}{}END{}'
(4)gawk进阶
(a)使用变量
(1)内建变量
处理数据流记录中,会遇到如下情况:
Rily Mullen
123 Main Street
Chicago, IL 60601
(312)555-1234
Frank Williams
456 Oak Street
Indianapolis, In 46201
(317)555-9876
如何使用不同的字段来表示每一行数据?
答:利用内建变量——输入字段分隔符FS,只要把输入字段分隔符FS设置成换行符,即:gawk 'BEGIN{FS="\n"}{}' filename。这就表明数据流中的每行都是一个单独的字段,每行上的所有数据都属于同一个字段。但是又会存在另外一个问题:无法判断一个新的数据行从何开始?
答:将FS设置成换行符,并将RS设置成空字符串。但是这要求数据记录间留一个空白行,gawk会把每个空白行当做一个记录分隔符。
(2)数据变量
ARGC和ARGV变量允许从shell中获得命令行参数的总数以及它们的值。
例如:gawk 'BEGIN{print ARGC,ARGV[1]}' data 结果:2 data
分析:ARGC变量表明命令行上有两个参数,gawk和data参数(记住,程序脚本并不算参数)。ARGV数组从索引0开始,代表的是命令,第一个数组值是gawk命令后的第一个命令行参数。注意:在脚本中引用gawk变量时,变量名前不加$。
ENVIRON:当前shell环境变量及其值组成的关联数组,它使用关联数组来提取shell环境变量,关联数组用文本作为数组的索引值,而不是数值。
NF:数据文件中的字段总数
FNR:当前数据文件中的数据行数 NR:已处理的输入记录数
FNR和NR的区别:如果只有一个数据文件作为输入时,FNR和NR的值是相同的;如果使用多个数据文件作为输入时,FNR的值会在处理每个数据文件时被重置,而NR的值则会继续计数直到处理完所有的数据文件。
(3)自定义变量
自定义变量可以是任意数目的字母、数字和下划线,但不能以数字开头。gawk变量名区分大小写。
在脚本中给变量赋值:gawk 'BEGIN{testing="this is a test.";print testing}' # 其中testing为自定义变量
在命令行上给变量赋值:gawk -f script.gawk n=3 filename #其中script.gawk是脚本,脚本中含有自定义变量n,并在命令行上设置变量n等于3。 注意:在命令行上设置的变量值在代码的BEGIN部分不可用。为了解决这个问题,可以用 -v 命令行参数来解决,它允许在BEGIN代码之前设定变量,-v命令行参数必须放在脚本之前。
(4)处理数组
数组变量赋值的格式:var[index]=element
遍历数组变量的格式:
for (var in array) 注意:var是索引值,不是数组元素值。
{
statements
}
删除数组变量:delete array[index]
(b)使用模式
(1)正则表达式
格式:gawk 'BEGIN{}/pattern/{}END{}' filename
(2)匹配操作符
匹配操作符是波浪线:~
gawk 'BEGIN{} $1 ~ /^data/{}END{}' filename # 过滤出filename中第一个字段以文本data开头的所有记录并利用脚本处理
不匹配操作符:!~
gawk 'BEGIN{} $1 !~ /^data/{}END{}' filename # 过滤掉filename中第一个字段以文本data开头的所有记录并利用脚本处理
(3)数学表达式
等于:== 小于等于:<= 小于:< 大于等于:>= 大于:>
gawk 'BEGIN{} x == y{}END{}' filename #找出filename中x==y的内容并利用脚本处理
(c)结构化命令
(1)if 语句
格式: if (condition) statement if (condition) statement1; else statement2
if (condition)
{
statement
} else
{
statement
}
(2)while语句 do-while语句
格式:
while (condition) do
{ {
statements statements
} } while (condition)
(3)for语句
格式:for(variable assignment; condition; iteration process){statements}
(d)格式化打印
格式化打印命令:printf 格式:printf "format string", var1, var2 ......
(e)内建函数
数学函数、字符串函数和时间函数
(f)自定义函数
格式:
function name([variables])
{
statements
}
12、正则表达式
正则表达式模式都区分大小写。只要定义的文本出现在数据流中,正则表达式就能匹配。
(1)基础正则表达式BRE
最基本的BRE模式是匹配数据流中的文本字符。
(a)纯文本
sed编辑器和gawk命令中的 /pattern/ 就是最基本的用标准字符串来过滤数据。
正则表达式中不仅仅局限于文本,还可以使用空格和数字。
(b)特殊字符
正则表达式识别的特殊字符包括:. * [ ] ^ $ { } \ + ? | ( )
(c)锚字符
两个特殊字符用来将模式锁定在数据流中的行首或行尾。
(1)锁定在行首
脱字符(^)定义从数据流中文本行的行首开始的模式。一般位于正则表达式模式中第一个字符,指明数据行必须以该文本模式开头;如果脱字符位于模式开头之外的位置,那么它就是一个普通的字符。
(2)锁定在行尾
美元字符($)定义了行尾锚点,将这个字符放在正则表达式模式之后来指明数据行必须以该文本模式结尾。
(3)组合锚点
在同一行中将行首锚点和行尾锚点组合在一起使用。利用这种方法和字符组结合能够匹配指定长度的文本。
例如:过滤数据流中的空白行:sed '/^$/' filename ---------------> 从文档中删除空白行的方法:sed '/^$/d' filename
(4)点号字符
点号(.)用来匹配除换行符之外的任意单个字符,它必须匹配一个字符。
(5)字符组
定义用来匹配文本模式中某个位置的一组字符。使用方括号定义一个字符组,方括号中包含所有出现在该字符组中的字符。
(6)排除型字符组
例如:匹配除ac和bc以外的模式:[^ab]c 注意:虽然是排除,但是仍然必须匹配一个字符,并与c搭配。
(7)区间
单破折线符号(-)在字符组中表示字符区间。例如:[0-9]表示0到9的任意数字。
在单个字符组中指定多个不连续的区间:[a-ch-m]表示匹配除d到g以外的字母。
(8)特殊字符组
匹配任意字母字符,不管大写或小写:[[:alpha:]] 匹配任意字母数字字符0~9、A~Z或a~z:[[:alnum:]]
匹配空格或制表符:[[:blank:]] 匹配0~9之间的数字:[[:digit:]]
匹配小写字母字符a~z:[[:lower:]] 匹配任意可打印字符:[[:print:]]
匹配标点符号:[[:punct:]] 匹配任意大写字母字符:[[:upper:]]
匹配任意空白字符—空格、制表符、NL、FF、VT或CR:[[:space:]]
(9)星号
在字符后面放置星号(*)表明该字符必须在匹配模式的文本中出现0次或多次。
匹配任意数量的任意字符:.* # 通常用于数据流中两个可能相邻或不相邻的文本字符串之间。
(2)扩展正则表达式
扩展正则表达式ERE包括了一些可供Linux应用和工具使用的额外符号。
gawk程序能够识别ERE模式,而sed编辑器不能。
(a)问号
问号(?)表明前面的字符可以出现0次或1次。
(b)加号
加号(+)表明前面的字符可以出现1次或多次,必须至少出现1次。
(c)使用花括号
ERE中的花括号允许为可重复的正则表达式指定一个上限,通常称为间隔,可用两种格式来指定区间:
m:正则表达式准确出现m次; m, n:正则表达式至少出现m次,至多n次。
注意:默认情况下,gawk程序不会识别正则表达式间隔,须指定gawk程序的--re-interval命令行选项才能识别正则表达式间隔。
格式:匹配模式bat中字符a必须至少出现m次,至多出现n次:gawk --re-interval '/ba{m,n}t/{}'
(d)管道符号
管道符号允许在检查数据流时,用逻辑OR方式指定正则表达式引擎要用的两个或多个模式,如果任何一个模式匹配了数据流文本,文本就通过测试,否则匹配失败。
格式:expr1|expr2|...
(e)表达式分组
圆括号()用于将正则表达式模式进行分组,该组会被视为一个标准字符。
13、字符串参数扩展
字符串参数扩展:允许对字符串进行搜索,在搜索关键词周围加上通配符(例如:*test*)可以搜索整个字符串。
格式:在字符串变量my_variable2中搜索是否包含关键字keyword,如果存在,则将variable的值保存到my_variable1中,否则将my_variable2的值保存到my_variable1中。
my_variable1=$(echo ${my_variable2/*keyword*/variable})
14、curl
curl命令允许从特定的web服务器上接受数据,与wget不同,它可以向web服务器发送数据。
15、wget
wget能够将web页面下载到本地linux系统中。
16、处理数据文件
(1)排序
sort命令对数据进行排序。
降序排序:sort -nr filename
(2)搜索数据
grep命令会在输入或指定的文件中查找包含匹配指定模式的字符的行。
格式:grep [options] pattern [file]
(3)压缩数据
gzip:用来压缩文件 gzcat:用来查看压缩过的文本文件的内容 gunzip:用来解压文件
(4)归档数据
tar命令用来将文件写到磁带设备上归档的,也能把输出写到文件里。
格式:tar function [options] object1 object2 ...
function参数定义了tar命令应该做什么。
解压.tgz文件:tar -zxvf filename.tgz 列出tar文件的内容,但是不提取文件:tar -xvf filename.tar
(5)在目录下查找文件
find命令用来在指定目录下查找文件。
任何位于参数之前的字符串都将被视为欲查找的目录名。如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。
格式:find path -option [ -print ] [ -exec -ok command ] {} \;
参数说明:path为目录,如果 path 是空字串则使用目前路径;path参数后面的是expression,如果 expression 是空字串则使用 -print 为预设 expression。