[工具] Shell 批量实现多个远程服务器执行命令 (单条命令版)

介绍:

基本信息

作者:朱明宇
名称:批量实现多个远程服务器执行命令 (单条命令版)
作用:批量实现多个远程服务器执行命令 (单条命令版)

使用方法

1. 将此脚本和清单 $list 文件放在同一目录下
2. 清单 $list 里每一个远程服务器名或 IP 地址占用 1 行
3. 在此脚本的分割线内写入相应的内容
4. 给此脚本添加执行权限
5. 执行此脚本

脚本分割线里的变量

1. execute=”top -bn 1 | head -1″ #指定要执行的命令
2. list=servers.txt #指定服务器清单

注意

执行脚本的用户要在远程服务器中有同名用户,此用户拥有免密钥 sudo su 权限,且能被本服务器免密钥 ssh

脚本:

#!/bin/bash

####################### Separator ########################

execute="top -bn 1 | head -1"
list=servers.txt

####################### Separator ########################

echo "WARNING: before execute this, please execute \"screen -S update\" command first"

read -p "will execute $execute on servers in $list, if you agree please input y : " b
echo "you input $b"

if [ "$b" != "y" ];then
        echo "you don't agree so exit now"
        exit 0
fi

num=0

for i in `awk '{print $1}' $list`
do
        let num++
        echo "$num $i"
        ssh -t $i "sudo -u root su - root -c \"$execute\""
        echo "$i has been done"
        echo
done

[内容] Shell 常用知识 (转载)

shell脚本总结

shell总结

 

shell脚本的本质是shell命令的有序集合

 

建立shell脚本的步骤:建立shell脚本,编写任意多行操作系统命令或shell命令,增加文件的执行权限,结束

 

shell变量

shell允许用户建立变量存储数据,但不支持数据类型。将任何赋给变量的值都解释为一串字符

shell有如下四种变量:用户自定义变量,位置变量,预定义变量,环境变量

 

用户自定义变量:

定义变量:COUNT=1

使用时前面加$:echo $COUNT

删除变量的赋值:unset COUNT

 

位置变量:

$0  与键入的命令行一样,包含脚本文件名

$1,$2...$9  分别包含第一个到第九个命令行参数

$#  包含命令行参数的个数

$@  包含所有命令行参数:“$1,$2...$9 ”

$?  包含前一个命令的退出状态

$*  包含所有命令行参数:“$1,$2...$9 ”

$$  包含正在执行进程的ID号

 

shell环境变量

CDPATH  用于cd命令的查找路径

HOME  用户主目录

PATH  路径

 

shell 程序和语句

shell程序由0到n条shell语句构成,shell语句包括三大类:功能性语句、结构性语句、说明性语句

 

说明性语句:以#开始的部分,不被解释执行

可以出现在程序的任意位置,可以单独一行,也可以接在执行语句的后面

 

功能性语句:任意操作系统命令、shell内部命令、自编程序、等

 

read  从标准输入读出一行,赋给后面的变量

read var   #把读入的数据全部赋给var

read var1 var2 var3     #把读入一行的第一、二个词分别赋给var1、var2,其他的都赋给var3

如果执行read语句时标准输入无数据,则程序在此停留等候,直到数据到来或终止运行

 

expr  主要用于简单的整数运算,包括 +  -  \*  /   %  等

 

 反撇号用于引用命令的运行结果

 

test  用于测试三种对象:字符串、整数、文件属性

可用[  ]代替,注意左右都至少一个空格

如:test  “$answer”  =  “yes”  #变量answer的值是否为字符串yes

test  $num  -eq  18  #变量num的值是否为整数18

test  -d  tmp    #测试tmp是否为一个目录名

 

 

 

结构性语句:条件测试语句、多路分支语句、循环语句、循环控制语句、后台执行语句

条件测试语句

if...then...else...fi

语法结构:

if  表达式

then  

命令表1  #一条或者若干条命令

else

命令表2  #一条或者若干条命令

fi

如果表达式为真,执行命令表1,否则执行命令表2

例子;

if [ -f S1 ]     #测试参数是否为文件

then

echo “File $1 exists”

fi

 

if [-d $HOME/$1]   #测试参数是否为目录

then

echo “File $1 is a directory”

fi

 

 

多路分支语句

case...esac

语法结构:

case 字符串变量  in     #case语句只能检测字符串变量

模式1)

命令表1

;;

模式2)

命令表2

;;

。。。。

*)                  # *表示其他所有

命令表n

;;

esac

例如:

case $1 in

file1)

echo “file1”

;;

file2)

echo “file2”

;;

*)

echo “others”

;;

esac

 

 

循环语句

for...do...done

当循环次数已知或者确定时,使用for循环语句来多次执行一条或一组命令,循环体由do和done来限定

for  变量名  in  单词表

do

命令表

done

说明:变量依次取单词表中的各个单词,每取依次单词,就执行一次循环体,循环次数为单词表中的单词个数,命令表中可以是一条或由分号隔开的多条命令

如果单词表是命令行上的所有位置参数时,可以省去  in  单词表

list=`ls`

for file in $list

do

if[ $1 = $file ]

then

echo “$file found”;

    exit; #退出shell脚本

fi

done

 

while...do...done

语法结构:

while  命令或表达式

do

命令表

done

说明:while首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,知道为假,退出循环

 

until...do...done

语法结构:

until 命令或表达式

do

命令表

done

与上面的相反

 

循环控制语句:

break  和  continue

break n   跳出n层

continue 马上跳转到最近一层循环的下一轮循环

continue  n  转到最近n层循环语句的下一轮循环上

 

 

 

shell函数

shell程序中,常把完成固定功能且多次使用的一组命令封装在一个函数中,每当要使用时,调用函数名即可

函数调用前必须先定义,即顺序上先定义函数,再调用

调用程序可以传递参数给函数,函数可以用return语句把运行结果返回调用程序

函数只在当前shell中起作用,不能输出到子shell中

 

shell函数定义格式

function funtion_name ()   #function可以省掉

{

...

}

 

函数调用方式

value_name = `function_name [arg1 arg2 ...]`    #函数结果返回给变量

或

function_name [arg1 arg2 ...]

echo $?           #获取函数返回的状态

 

函数变量的作用域

全局作用域:在脚本的其他地方都可以访问该变量

局部作用域:只能在声明的作用域内访问

 

局部变量的声明: Local  variable_name = value

 

脚本调试:

跟踪脚本执行结果:

在希望开始调试的地方插入 set -x

在希望结束调试的地方插入 set +x

 

 

---------------------------------------------------------------------

---------------------------------------------------------------------

Bash shell结构

1:shbang行:脚本的第一行,告之内核用哪个shell解释shell脚本,由#!加shell的完整路径组成

2:注释:#后面的为注释,可以在一行后

3:shell通配符或元字符:shell中字符意义比较特殊,如* ? [] > < 2> >> |等,防止这些字符被解释,则必须引用他们

4:局部变量:局部变量作用域在本shell中

5:全局变量:又称为环境变量,由内置的export命令创建,作用域在本shell及子shell中

6:提取变量值:$

7:参数:可以从命令行传递参数给脚本

8:命令替换:`A` $(A)  结果可以赋给一个变量或代替所在位置

---------------------------------------------------------------------

正则表达式

正则表达式是一种字符模式,在查找过程中匹配指定的字符,可以用特殊的元字符来控制它们,正则表达式都被置于两个正斜杠//之间

元字符:表达的是不同于字符本身的含义

本书中的元字符有两类:shell元字符、正则表达式元字符,它们各司其职,shell元字符是由shell解析的,就是下面所讲的文件名置换;正则表达式元字符是由各种执行模式操作的程序来解析的,如vi、grep、sed、awk

---------------------------------------------------------------------

正则表达式元字符:

^  行首定位

$  行尾定位

.  匹配单个字符

*  匹配0或多个重复的位于*前的字符

[]  匹配指定组字符中的任意一个 ;如[LlT]

[-] 匹配指定范围内的字符 ;如[x-yA-Z0-8]

[^] 匹配不在指定组内的字符

[^ - ]跟上面的相反

\  转移跟在后面的字符     #转义元字符,使之不被解释

\< 词首定位符     #定位以什么开头的词

\> 词尾定位符     #定位以什么结尾的词

---------------------------------------------------------------------

grep 家族

grep家族由grep、egrep、fgrep组成 

grep命令在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行

一般格式:grep  [选项]   基本正则表达式  [文件]   

选项:-n 显示行号  -i 大小写不敏感  -w表达式作为词来查找,也就是不是一个词的一部分  -r 递归查找

基本正则表达式:可为字符串,如果为字符串,最好用“”如果是模式匹配,用‘’调用变量时,也应该使用“”

文件:可以为多个文件;如 A1 A2

常用举例子

grep -n “your” www    #文件www中查找含有your单词的行,且输出行号

grep -nw “your” www    #文件www中查找含以your做单词的行,且输出行号

grep -nr ‘[a-zA-Z0-9].you’ ./  #递归./ 中查找含有以a-z A-Z 0-9开始的单词的行,且输出行号

---------------------------------------------------------------------

find命令及xargs

find pathname -options [-print -exec -ok]

常用的options为name 此时记住要用引号将文件名模式引起来

find ./  “*org.txt”   #在当前目录及子目录中寻找以org.txt结尾的文件

find 找到文件后可用xargs对其操作

find ./  “*org.txt” | xargs ls

find ./  “*org.txt” | xargs grep “device”  #在结果中搜索device

---------------------------------------------------------------------

启动

系统启动后

->init->getty进程

->/bin/login  初始化环境,启动shell

->/bin/bash 执行/ect/profile,执行~/.bash_profile ~/.bash_login ~/.profile,执行~/.bashrc

->等待用户输入

---------------------------------------------------------------------

环境

一个进程的环境包括:变量等,它定义了可以从一个进程继承到下一个进程的特性

用户的shell配置定义在shell初始化文件中,bash shell有许多启动文件,这些文件可以执行source命令,对一个文件执行source命令会使得这个文件中的所有设置称为当前shell的一部分,也就是说不会创建子shell

登陆时,会执行~/.bash_profile文件执行source命令,如无,则source ~/.bash_login,若无,则source ~/.profile,这三个文件只能source一个,再source ~/.bashrc

~/.bashrc:包含特定的变量和别名,当一个新的bash shell启动或bash脚本启动时会自动执行source ~/.bashrc

在当前提示符下输入shell或bash启动的是子shell

/etc/bashrc:系统级的函数和别名可以在/etc/bashrc文件中设置,主提示符一般在这设置

~/.profile:是一个用户定义的初始化文件,它是被Bourne shell使用的,因此不能包括对bash shell的特定设置,运行bash时只有没找到其他文件时才source此文件,它允许用户定制和修改shell环境,也可以放应用程序的初始化

---------------------------------------------------------------------

source命令或dot命令(.)  和  ./命令

source命令式内置的bash命令,来自C shell

dot命令也就是. 来自Bourne shell

二者完全一样,都是一个脚本名作为参数,shell将在当前的shell环境中执行这个脚本,也就是不启动子shell,脚本中的设置的所有参数将成为当前shell环境的一部分。

./执行脚本时是创建子shell,脚本中的设置参数在脚本退出后就无效了。

 

例子:在家目录下的.bashrc中加入WANG=”ni hao”

然后. .bash.rc

此时执行内容为 echo “$WANG”的 脚本

 

如用 ./sh.sh 则无输出  #./执行时是在起一个子shell

如用source sh.sh或 . sh.sh则输出ni hao  #source是在本shell中执行

---------------------------------------------------------------------

bash shell元字符(通配符)

\  按字面含义解释后面的那个字符

&  在后台处理的进程

; 分隔命令

$  替换命令

*  匹配任意字符

?  匹配任意单个字符

[...] 匹配[]中的任意一个字符

[!...] 不匹配[]中!的任意一个字符

(cmds)  在子shell中执行命令

{cmds}  在当前shell中执行命令

---------------------------------------------------------------------

文件名置换

计算命令行时,shell会用元字符来缩写能够匹配某个特定字符组的文件名或路径名

将元字符展开为文件名或路径名的过程称为文件名替换或globbing

*    匹配文件(夹)名中的任意字符串

如:ls app*

cd cmdd*

?    匹配文件(夹)名中的任意一个字符

[...] 匹配[]中的任意一个字符

[!...] 不匹配[]中!的任意一个字符

如:ls [a-z]*.o   #匹配以a-z开头的已.o结尾的文件

ls [!0-9]*.o     #匹配以非0-9开头的已.o结尾的文件

---------------------------------------------------------------------

命令执行顺序

命令1 && 命令2  #命令1执行成功才会执行命令2

命令1 || 命令2  #命令1执行不成功才会执行命令2

用() 和 {}将命令结合在一起

 

 

---------------------------------------------------------------------

Bash shell变量

变量可分为两种:局部变量和环境变量

局部变量只在创建他们的shell中可用,环境变量作用域可以扩展到子shell中去

变量命名规则:可以是字母、0-9、下划线组成,必须以字母或下划线开头,其他字符都标志着变量名的终止,变量名大小写敏感

有两个内置命令可以用来创建变量,他们是declare、typset,其选项可以控制变量的设置方式,建议使用declare.

格式:declare  [选项]  变量=值

选项:-x  将变量设置成环境变量

      -r 将变量设置成只读变量

      -a 将变量当一个数组

---------------------------------------------------------------------

创建局部变量

1:变量赋值:变量=值    #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符

2:内置命令declare  变量=值  #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符

例子:

设置:round=world 或 round=”world nice”  #“”保护空白符

设置:declare round=world

输出:echo $round

设置:file.bak=”xxxx”   错,变量名中出现非法字符

local函数:函数内创建局部变量可以用local函数

---------------------------------------------------------------------

创建环境变量

环境变量,又被称为全局变量,作用域可以扩展到子shell中,通常环境变量用大写

环境变量是已经用export内置命令导出的变量,如果想设置环境变量,只需在设置变量时或赋值后使用export命令即可,declare 带-x也是设置环境变量

设置环境变量:

1:export 变量=值  #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符

2:变量=值; export 变量    #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符  

3:declare -x 变量=值  #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符

---------------------------------------------------------------------

设置只读变量

只读变量是不能被重新定义或复位的特殊变量,但是如果使用declare定义的变量,可以重定义,不能复位

设置:name=”TOM”

readonly name   #设置只读

unset name  #不能复位

name=Jem  #不能重定义

设置:declare -r city=”shanghai”

unset city #不能复位

declare city=“beijin” #可以

---------------------------------------------------------------------

提取变量的值

在变量前加$

---------------------------------------------------------------------

复位变量

只要不被设置只读,局部变量和环境变量都可以用unset命令复位

格式:unset 变量名

---------------------------------------------------------------------

显示变量值

1:echo [选项]  变量   #echo将他的参数显示到标准输出上

选项:-e   #允许解释转义字符,如echo -e “\a”  \a转义为报警

如:echo The name is $NAME

echo -e “\a”  #报警

2:printf命令

---------------------------------------------------------------------

变量扩展修饰符

可以用一些专用修饰符来测试和修改变量,修饰符首先进行简单的条件测试,检查某变量是否已被设置,然后根据测试结果给变量赋值

${VA:-word}  #如变量VA已经设置且非空,则代入其值,否则代入word   临时替换默认值 

${VA:=word}  #如变量VA已经设置且非空,则代入其值,否则VA设置为word,代入VA永久替换默认值

${VA:+word}  #如变量VA已经设置且非空,则代入word,否则代入空值   临时替换默认值

${VA:?word}  #如变量VA已经设置且非空,则代入其值,否则输出word且从shell退出  基于默认值创建错误信息

 

注:不加冒号时,值为空也被认为已经设置

如:echo ${name-Joe}  #结果为空

echo ${name:-Joe}  #结果为Joe

echo ${namex:?”namex is undefined”}  

echo ${y?}  #如果y未设置,否则输出parameter null or not set

 

${VA:offset}  #获取变量VA值中位置从offset开始的字串

${VA:offset:length}  #获取变量VA值中位置从offset开始长度为length的字串  创建字串

如:var=notebook

echo ${var:0:4}   #结果note

---------------------------------------------------------------------

子串的变量扩展

模式匹配变量用来在串首或串尾截掉串的一部分,常用语删除路径名的头或尾

${变量%模式}  #将变量值的尾部与模式进行最小匹配,并将匹配到的部分删除

${变量%%模式} #将变量值的尾部与模式进行最大匹配,并将匹配到的部分删除

${变量#模式}  #将变量值的头部与模式进行最小匹配,并将匹配到的部分删除

${变量##模式} #将变量值的头部与模式进行最大匹配,并将匹配到的部分删除

${#变量}      #替换为变量中的字符个数,如果是*或@ ,长度则是位置参量的个数

如:

pathname=”/usr/bin/local/bin”

echo ${pathname%/bin*}  #结果/usr/bin/local/

echo ${pathname%%/bin*}  #结果/usr

echo ${pathname#/usr}  #结果/bin/local/bin

echo ${pathname##/usr}  #结果bin

echo ${#pathname}  #结果8

---------------------------------------------------------------------

位置参量

下面这组专用内置变量常称为位置参量,通常被shell脚本用来从命令行接受参数,或被函数用来保存传递给它的参数

$0  #指当前shell脚本的名称

$1-$9  #代表第一个到第9个位置参量

${10} ${11} #第10、11个位置参量,不用$10,$11

$#  其值为位置参量的个数,不含$0

$*  其值为所有的位置参量

$@  同$*

“$*”  其值为“$1 $2 $3”

“$@”  其值为“$1”“$2”“$3”

位置参数可以用set命令来设置、重置或复位

set --   #清除所有的位置参数

---------------------------------------------------------------------

其他特殊变量

$    #当前shell的pid

_    #当前sh的选项设置

?    #已执行的上一条命令的退出值

!    #最后一个进入后台的作用的pid

---------------------------------------------------------------------

引用

用来保护特殊的元字符不被解释和禁止参量扩展

引用有三种方式:反斜杠、单引号、双引号

需要引用的特殊元字符有:

;

&

()

{}

|

< > 

空格 tab 换行符

$ 

* [] ? 

1:单引号和双引号必须成对出现

2:单引号保护特殊元字符免受解释,双引号也能,但双引号允许处理变量替换字符$和命令替换字符``和\

3:双引号可以保护单引号,单引号可以保护双引号

4:如果有不匹配的引号,bash会出现次提示符

反斜杠:反斜杠用于引用(或转义)单个字符,使其免受解释。

单引号中的反斜杠不会被解释

如果在双引号中,反斜杠将保护$ ``和反斜杠免受解释

单引号:成对出现,保护所有元字符不被解释,打印双引号就必须用双引号将其括起来,或反斜杠转义

双引号:同单引号,但是允许进行变量替换$和命令替换``和\

 

简言之:单引号中什么都不被解释。双引号中$ `` \这三个会被解释,如不想解释用\转义

注意:``同$()是一样的,所以$(date)也会展开

---------------------------------------------------------------------

命令替换

命令替换的用处是将命令的输出结果赋给一个变量或将命令的输出结果代入命令所在位置

bash 允许使用两种格式:`命令`   和  $(命令)

执行扩展时,bash先执行命令,然后返回命令的标准输出,输出结果末尾的换行符都将被删除,如果不想删除,可用“”括起,如:echo “$(cal)”

如:echo “this is `date +%H`”   #this is 09

d=$(date)  #d存放命令date的结果

`命令`  \保留字面意思,除非后面跟$ ` \ 且``中$  \生效,可用\转义之,``中再有``的话必须用\转义

$(命令)  中的所有特殊字符都不会解释

命令替换可以被嵌套,``必须使用\`转义,如echo `basename \`pwd\` `  #其中转义后的`pwd`也是当做命令替换的,如:$(basename $(pwd))

---------------------------------------------------------------------

数组

bash 中可以创建一维数组,数组允许将一列词放到一个变量名中,可以用内置命令declare -a创建,或直接给变量名一个下标来创建,如x[0]=5   索引值为从0开始的整数,数组无上限,索引也不必是有序数。

取出数组中某个元素,语法为:${数组名[索引]}

创建数组:

declare 、local 、read-only内置命令也可以带-a选项来声明一个数组。read -a是读取一列词到数组中

declare -a va_name=(item1 item2 item3 ...)

declare -ar va = {item1 item2 item3 ...}

states=(ME [3]=CA [2]=CT)  #数组states第0元素为ME  3元素为CA  2元素为CT

declare -a nums=(45 33 100 65)

name=(TOM Dick Harry)

echo ${va_name[*]}   #输出数组所有元素

echo ${#va_name[*]}  #输出数组大小

取消定义:unset name 或 unset name[2]

---------------------------------------------------------------------

函数

bash函数用于在当前shell环境(不派生子shell)通过函数名执行一组命令,函数常常用于提高脚本的模块化程度。

函数可被重复调用。函数必须定义后才会被调用

定义函数:有两种格式声明一个bash函数

1:函数名后跟一对圆括号,再跟函数定义

function_name () { commands;commands; }

2:function关键词后跟函数名及函数定义,圆括号可选

function function_name { commands;commands;}

function function_name () { commands;commands;}

注意:命令之间用;隔开,最有一条命令必须以分号终结。花括号两侧空格是必须的。

传递给函数的任何参数被当做函数内的位置参数,一个函数的位置参数相对于函数来说是局部的

内置命令local允许在函数定义中创建局部变量

 

函数可以递归调用本身

函数中的命令是在当前shell环境下执行

全局函数:同变量一样,函数作用域可以扩展到子shell,只要用export -f全局化函数

export -f 函数名

说明:当函数命令列在单独的行,可以不用分号,最后一条还是需要。如果列在同一行,必须用分号隔开

如:function welcome { echo “Hi $1 and $2”; }

welcome tom joe  #传递参数给函数,结果为Hi tom and joe

set jane anna lizzy

echo $1 $2

jane anna

unset -f welcome #清除函数定义

 

列出和清除函数

declare -f #列出该shell中定义的所有函数及他们的定义

declare -F #同上,只列出函数名

unset -f   #清除函数定义

---------------------------------------------------------------------

管道

管道(pipe)将管道符左侧命令的输出作为到管道符右侧命令的输入,一条管道线可能不止一个管道

管道符用竖杠 | 表示,一般形式:命令1 | 命令2 | 命令3

---------------------------------------------------------------------

shell内置命令

shell中有许多内置到它的源码中的命令,shell无需到磁盘中定位他们,执行速度速度快很多。

常见内置命令如下:

:   #空命令

.   #在当前进程的环境下执行程序,同source

alias #命令重命名

unalias #删除重命名

bg  #将作业放到后台

cd 

exit

fg #将作业放到前台

jobs #列出放在后台的作业

set #设置选项和位置参数

unset #删除变量值或函数

declare

export

---------------------------------------------------------------------

Bash shell编程

shell脚本:当命令不在命令行上执行,而是通过一个文件执行时,该文件被称为shell脚本,脚本以非交互的方式运行。它先查找环境变量所指定的环境文件,通常为.bashrc,然后从该文件开始执行,然后才开始执行脚本中的命令

创建shell脚本的步骤:

1:第一行:#!/bin/bash

2:编写内容

shell脚本结构:由一组Unix/linux命令、bash shell命令、程序结构控制语句、注释 组成

3:增加执行权限  chmod +x files

---------------------------------------------------------------------

读取用户输入

read命令

read是一个内置命令,用于从终端或文件读取一个输入行,直到换行符,行尾的换行符被转换成一个空字符,如果后面未跟变量名,则读取的行被赋给内置变量REPLY,可以用read中断脚本的运行,直至输入回车键

read var                 #把读入的数据全部赋给var

read var1 var2 var3     #把读入一行的第一、二个词分别赋给var1、var2,其他的都赋给var3

---------------------------------------------------------------------

算术运算

整数运算(declare和let命令)

declare命令:可以用declare -i 定义整形变量,如果给一个整形变量赋一个字符串,则bash将把变量赋值为0,可以对已定义的整形变量执行算术运算(如果未定义为整形变量,内置的let命令也允许算术操作),如果给整形变量赋一个浮点数值,则bash报语法错误。数字可以用不同基数的数字表示

如:declare -i num

num=5 + 5 #错

num=5+5  #对

num=”5 + 5” #对

num=5.6 #错

 

declare -i  将列出所有已经设置的整形变量及其值

 

用不同的基数表示数字

格式:variable=base#number

如:declare -i x=017

x=2#101

x=8#17

let命令:let命令式bash shell内置命令,用来执行整形算术运算和数值表达式测试;可用(())表示let命令

let命令在执行算术运算时,不需要用$来展开变量,参数含有空格则用“”包含

如:let “i = i + 2”

---------------------------------------------------------------------

位置参数

用户可以通过命令行向脚本传递信息,跟在脚本名后的用空白符分隔的每个词都称为参数,可以在脚本中使用位置参数来引用命令行参数

shell环境中的位置参数作用域在本shell,shell脚本执行时跟在后面的参数相当于局部的位置参数,只对本脚本生效

如:脚本内容 echo “$1”

执行时 source sh.sh wang  #则输出wang

如果在命令行set hahaha

执行时 source sh.sh wang  #则输出wang

执行时 source sh.sh  #则输出hahaha

 

set命令与位置参数

可以用set命令设置或重设位置参数

带参数的set命令将重置位置参数,重置的是shell环境中的位置参数。清除所有位置参数,可以用set -- 命令

---------------------------------------------------------------------

条件结构和流程控制

条件结构能够根据某个特定的条件是否满足,来执行相应的任务

bash可以检测两种类型条件:命令成功或失败,表达式为真或假。在任何一种类型的测试中,都要使用退出状态,为0表示命令成功或表达式为真,非0表示命令失败或表达式为假。退出状态保存在状态变量?中
简言之:bash中执行命令成功与否和表达式为真或假都会改变退出状态变量?

 

 

内置命令test

单方括号的test命令:通常使用内置的test命令测试表达式的值,test命令可以被链接到方括号上,这样即可使用单独的test命令,也可通过把表达式用单括号括起来,来测试表达式的值

用test命令或[]测试表达式时,表达式中的shell元字符不会被解释。由于对变量进行单词分离,因此包含空白符的字符串必须用引号括起来

双方括号的test命令:用[[]]来测试表达式的值,其中对变量不进行单词分离,但可以通过元字符扩展进行模式匹配。包含空白符的字符串必须用引号括起来,如果一个字符串(不管含不含空白符)仅仅是在表达式中作为一个普通字符串,而不是一个模式的一部分,则必须用引号括起来

逻辑操作符&&、||代替了与test命令一起使用的-a -o选项

 

说明:test可以用来测试字符串、数字、文件。test命令中表达式等号两侧必须有空格。单方括号第一个方括号后必须有空格,表达式两侧必须有空格。

简言之:

[]的测试表达式:表达式可为字符串比较、数字比较、文件测试。表达式等号两侧必须有空格,方括号必须有空格。表达式中的shell元字符不会被扩展。对变量进行单词分离,所以包含空格时必须用引号括起来

[[]]的测试表达式:表达式可为字符串比较、数字比较、文件测试。表达式等号两侧必须有空格,方括号必须有空格。表达式支持shell元字符,如果为普通字符串,防止误认为模式,必须用双引号括起来。支持逻辑&& || ,对应test中的-a -o   ,其中对变量不进行单词分离,即使变量由多个词组成也不需要双引号括起来

 

let和带双圆括号的算术运算符(())

对于计算算术表达式,可以不用test而用let命令,let命令含有丰富的操作符,let命令等同(())

(())中的变量不需要使用$,操作符两侧必须空格,圆括号两侧必须空格

简言之:let命令更适合整形算术运算和数值表达式测试

---------------------------------------------------------------------

if命令

if 结构后面的命令可以是bash内置命令或可执行程序,如ls

bash shell中跟在if后面的则是一条或一组命令。

 

exit 命令和变量?  exit用于终止脚本并返回到命令行

检查空 检查变量的值是否为空时,必须用双引号把空括起来,否则test命令失败

 

if 命令

then

命令

elif 命令

then

命令

elif 命令

then

命令

fi

---------------------------------------------------------------------

null命令(shell内置命令)

:代替null命令

null命令不做任何事,只是返回退出状态0(注意没退出,不同于exit 0)

---------------------------------------------------------------------

case命令

格式:

case 变量 in

表达式1)

命令组

;;

表达式2)

命令组

;;

...

*)

命令组

;;

esac

变量的值逐一与表达式相比,符合则执行命令组,并跳到esac后继续执行

表达式可以使用shell通配符,还可以使用 | 将两值相或

---------------------------------------------------------------------

循环命令

bash shell提供三种类型的循环:for   while   until

---------------------------------------------------------------------

for命令

格式:

for  变量  in   词表

do

命令组

done

注:词表可以通过执行命令获得,如  for  W  in $(date)

词表支持shell元字符:如 for file in memo[1-5]  

注意词表是$* $@ “$*” “$@”时的区别

如果没有“in 词表”则相当于“ for 变量 in $* ”

如果命令行参数为*,则它表示当前目录下的所有文件。

---------------------------------------------------------------------

while命令

格式:

while 测试命令

do

命令(命令组)

done

注:while 后的测试命令可以用test 或let或其他

---------------------------------------------------------------------

until命令

同while命令,只不过相反,也就是until 后的命令执行不成功时执行命令组

---------------------------------------------------------------------

循环控制命令

shift命令

shift 命令将参数左移指定次数,如:shift 5,没给参数时移动一次,当不够移动时,输出信息。

shift常用于while循环中遍历位置参数列表时。

如:while (( $# > 0 ))

do

echo $1   #$1值不断变化

shift

done

 

ture命令:总是已状态0退出

 

break命令

break用于跳出循环,层数为跳出几层

continue命令 跳过本次循环,继续下次,参数为调到哪一层循环起点,默认为跳到最近一层

---------------------------------------------------------------------

I/O重定向 与 子shell

shell可通过管道或重定向将输入从文件输入改为从循环读取输入,输出到循环改为输出到文件

shell启动一个子shell来处理I/O重定向和管道,循环结束后,在循环中定义的所有变量对脚本的其余部分都是不可见的

重定向一般是到文件,管道一般是到命令

将循环的输出重定向到一个文件:bash循环的输出不仅可以送到标准输出,还可以通过管道送到文件

将循环的输出管道到一个命令

---------------------------------------------------------------------

后台执行循环

循环可以在后台执行,这样就可以继续往下执行其他程序而不必等待循环处理全部完成

---------------------------------------------------------------------

函数

函数在当前环境中运行,函数共享调用它的脚本中的变量,还允许给函数传递参数,可以使用local功能在函数内部创建局部变量

在函数中调用exit将退出整个脚本。

函数中的return语句,返回函数执行的最后一条命令的退出状态,或返回指定参数值

使用export -f把函数导出到子shell

使用declare -f可以列出所有的函数名及其定义

如果函数保存在其他一些文件中,可以用source和dot命令把他们载入到当前脚本中

函数可以递归调用,次数没限制

 

清除函数

从内存中清除某个函数,使用unset命令

unset 函数名

 

函数的参数和返回值

当前shell环境中的变量对函数是可见的,在函数中对环境所做的任何改动也是会对shell环境生效的。

函数可以使用位置参数向函数传递参数,位置参数是函数私有的,也就是说,函数对参数的操作不会影响在函数外使用的任何位置参数

内置local功能:函数私有的局部变量,在函数退出后随即消失。

内置return命令:用来退出函数并将控制回转到程序调用函数的位置,如果未给return赋值,则返回最后一条命令的退出状态,如果赋值了,则该值保存在变量?中。可以是0-255之间整数。

获取函数的结果可以用 命令替换,如:$(函数名)  `函数名`

函数可以定义在文件中,当需要时,调用source或dot命令跟上函数名就能激活文件中的函数,函数会被加载到shell内存空间

---------------------------------------------------------------------

调试

带-n选项的bash命令,能对脚本进行语法检查,但不去运行任何一条命令,如语法错误,则报错,否则不显示任何内容

最常见的调试脚本的手段是用带-x选项的set命令,或是调用带-x选项和脚本名为参数的bash

此时shell对脚本的每条命令处理过程为:先执行替换,接在显示,再去执行它。shell显示脚本中的行时,会在行首添加加号+

调试选项:

bash -x 脚本名  #回显   在变量替换之后,执行命令之前,显示脚本的每一行

bash -v 脚本名  #详细   在执行之前,按输入的原样打印脚本中的各行

bash -n 脚本名  #不执行 解释但不执行命令

set -x  #打开回显  跟踪脚本执行

set +x  #关闭回显  关闭跟踪功能

---------------------------------------------------------------------

调试shell脚本

风格问题

1:加注释

2:定义有意义的变量名

3:确保健壮性

错误类型

---------------------------------------------------------------------
————————————————
版权声明:本文为CSDN博主「wangchaoqun1997」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wangchaoqun1997/article/details/36480131

注明:所有转载内容皆直接从被转载文章网页的标题和内容的文本中复制而来

CC 4.0 BY-SA 版权协议网址:https://creativecommons.org/licenses/by-sa/4.0/deed.z

[工具] Shell 批量检测服务器 TCP 端口的联通状态 (telnet 版)

介绍

基本信息

作者:朱明宇
名称:批量检测服务器 TCP 端口的联通状态
作用:批量检测服务器 TCP 端口的联通状态,并将此服务器无法联通的端口存储到 $checklist 文件里

使用方法

1. 将此脚本和端口清单 $portlist 文件放在同一目录下
2. 端口清单 $portlist 每一个端口占用一行,格式为:<IP address corresponding to the port number to be connected>:<port number to connect>:<port functions>,并和此脚本放在同一目录下
3. 在此脚本的分割线内写入相应的内容
4. 给此脚本添加执行权限
5. 执行此脚本,并将要测试的服务器 IP 地址跟在脚本的后面,例:. <script> <server IP address 1> <server IP address 2> ……

脚本分割线里的变量

1. portlist=tcp_ports.txt #存放要测试的 TCP 端口的文件
2. checklist=tcp_ports_checklist.txt #存放测试结果的文件

注意

1. 此脚本执行前必须要先保证执行本脚本的用户能无密码 ssh 远程这些远程服务器
2. 此脚本会清空 $checklist
3. 执行此脚本前确保 telnet 命令已经安装
4. 执行此脚本可能有些慢

脚本

#!/bin/bash

####################### Separator ########################

portlist=tcp_ports.txt
checklist=tcp_ports_checklist.txt

####################### Separator ########################

echo  > $checklist
maxnum=`cat $portlist | wc -l`

for hosts in $*
do

        echo $hosts >> $checklist

        for i in `seq 1 $maxnum`
        do

                ips=`sed -n $[i]p $portlist | awk -F':' '{print $1}'`
                ports=`sed -n $[i]p $portlist | awk -F':' '{print $2}'`
                remarks=`sed -n $[i]p $portlist | awk -F':' '{print $3}'`

                ssh $hosts "(sleep 1;) | telnet $ips $ports 2>&1" | grep 'timed out' >> $checklist

                if [ $? == 0 ];then
                        echo "`sed -n $[i]p $portlist`" >> $checklist
                        echo >> $checklist
                fi

        done

        echo >> $checklist

done

[命令] Linux 命令 sed (显示或修改文件的行)

内容一:sed 基础

1.1 sed 的工作原理

1) 从第 1 行开始 1 行 1 行地读取文件里的内容
2) 每读取 1 行就将内容存入到 pattern space (模型空间) 里面,pattern space (模型空间) 里的内容默认会自动显示出来
3) 在 pattern space (模型空间) 中执行 sed 命令
4) 再显示 pattern space (模型空间) 中的内容然后将其清空
5) 之后重复以上操作再开始读取文件里的下 1 行
6) pattern space (模型空间) 里的内容可以存储到 hold space 里面

1.2 sed 格式

# sed <option> <parameter> <file>

1.3 sed 选项

1) -n 或 –quiet 或 –silent 仅显示处理后的内容,没处理的内容就不显示了,也就是仅显示非标准输出的内容
2) -i 实现数据的变更
3) -e <script> 或 –expression=<script> 这样可以一次匹配多个参数
4) -r 支持扩展正则
5) -f <script file> 或 –file=<script file> 以指定的脚本文件来处理输入的文件
6) -h 或 –help 显示帮助内容
7) -V 或 –version 显示版本信息


补充:
1) pattern space (模型空间) 相当于处理内容的流水线
2) hold space (保持空间) 相当于暂时存储内容的仓库

1.4 sed 的参数

1) p 先将每行的内容以标准输出的形式显示 1 遍,再将每行的内容以非标准输出的形式再显示 1 遍。不改变是否跳过下 1 行的属性,也就是如果前面有一个 N 参数,则跳过往下第 1 行接着执行往下第 2 行,如果前面没有任何参数,则直接执行往下第 1 行
2) P 先将每行的内容以非标准输出的形式再显示 1 遍,但是如果是 2 行组合在一起的话只显示第 1 行的内容,也就是只显示分行符 “/n” 之前的内容,再将每行的内容以标准输出的形式显示 1 遍。不改变是否跳过下 1 行的属性,也就是如果前面有一个 N 参数,则跳过往下第 1 行接着执行往下第 2 行,如果前面没有任何参数,则直接执行往下第 1 行
3) n 将每行的内容以标准输出的形式显示 1 遍,并提前读取下 1 行的内容,将下 1 行的内容覆盖当前行的 pattern space (模型空间),也就是下 1 行变成了当前行,再将当前行的内容以标准输出的形式显示一遍 (如果此时得到的内容是非标准的形式则不显示)。然后跳过往下第 1 行接着执行往下第 2 行。另外,如果往下 1 行不存在则直接停止所有命令,如果当前面的条件匹配时则放弃所有后面的命令
4) N 提前预读下 1 行,将下 1 行的内容添加到本行的 pattern space (模型空间) 后面,但是本行的内容和下 1 行的内容之间依旧存在分行符 “/n”,再将当前行的内容以标准输出的形式显示一遍。然后跳过下第 1 行接着执行往下第 2 行。另外,如果下 1 行不存在则以标准的形式显示当前 pattern space (模型空间) 里的内容并直接停止所有命令,如果当前面的条件不匹配时则放弃执行 N 命令直接执行后面的命令
5) = 以非标准输出的形式显示每 1 行是第几行,在行数后面以标准输出的形式显示行的内容
6) a 在某 1 行后面添加 1 行的内容
7) i 在某 1 行前面插入 1 行的内容
8) c 替换某 1 行的内容
9) g 将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除
10) G 将 hold space (保持空间) 中的内容 append (添加) 到 pattern space (模型空间) 分行符 “/n” 后
11) h 将 pattern space (模型空间) 中的内容拷贝到 hold space (保持空间) 中,原来的 hold space (保持空间)里的内容被清除
12) H 将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后
13) d 删除 pattern space (模型空间) 中的所有行,并执行下 1 行
14) D 删除 pattern space (模型空间) 中的第 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行
15) s 替换某行的某些内容
16) y 替换某行的某些内容,和 s 的作用一样,但是功能没有 s 丰富
17) x 将当前 hold space (保持空间) 和 pattern space (模型空间) 内容互换,hold space (保持空间) 用来保存临时内容, pattern space (模型空间) 是本行的内容,注意 hold space (保持空间) 和 pattern space (模型空间) 的内容互换并不改变这些内容是第几行的,例如在 pattern space (模型空间) 里的内容是第 3 行的,则需要 3p
18) r 读取某一个文件里的内容
19) w 将内容写入一个文件
20) q 退出,前面可以跟退出的条件,后面可以跟退出代码
21) b 参数,设置标签分支,如果条件不成立,则对标签的位置进行跳转,如果标签省略了,则分支会一直到末尾
22) t 参数,设置标签分支,如果条件成立,则对标签的位置进行循环跳转,直到所有可进行的操作都完成后才停止,如果标签省略了则标签分支会一直到头部。在 t 和变迁之间的步骤是会循环执行的区域


注意:
1) 当多个参数进行组合时,多次标准输出最后会合并成只显示 1 次
2) 当多个参数进行组合时,当 1 个参数后面还有参数时,产生的输出不会直接显示而是传输给下 1 个参数进行处理,如果此次显示是非输出的形式,传递给下 1 个参数处理以后也会以非输出的形式输出

内容二:sed 使用 p 参数、P 参数、n 参数、N 参数和 = 参数显示某些行数据的案例

2.1 显示第 2 行的内容

# sed -n 2p test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.2 显示第 2 行到第 4 行的内容

# sed -n 2,4p test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.3 显示不是第 1 行的内容

# sed 1!p test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.4 显示最后 1 行的内容

# sed -n '$p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

或者:

# sed 'N;D' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.5 显示包含 eternalcenter 的内容

# sed -n '/eternalcenter/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.6 显示以 eternalcenter 结尾的内容

# sed -n '/eternalcenter$/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.7 显示包含 eternalcenter 的行的行号,并将此行的上一行的内容,本行的内容和下一行的内容显示出来

# sed -n -e '/eternalcenter/{=;x;1!p;g;$!N;p;D;}' -e h test.txt


补充:
1) 当执行到包含 eternalcenter 内容的行时
2) 执行 /eternalcenter/ 判断当前包含 eternalcenter 内容则为真,如果为真,执行 = 参数,以非标准输出的形式传输每 1 行是第几行,在行数后面以标准输出的形式传输行的内容,此时这些内容存放在 pattern space (模型空间) 中并传输给 x 参数
3) 执行 x 参数,将当前 hold space (保持空间) 和 pattern space (模型空间) 内容互换,并传输给 p 参数。在执行 x 参数前 hold space (保持空间) 里的内容是由上一行执行 h 参数时保存的,所以执行 x 参数后 pattern space (模型空间) 的内容是上一行的内容。注意 hold space (保持空间) 和 pattern space (模型空间) 的内容互换并不改变这些内容是第几行的
4) 执行 1! 判断当前行不是第 1 行则为真,如果不是第 1 行,如果执行 p 参数,将此时 pattern space (模型空间) 的内容以标准输出的形式进行显示,再将 pattern space (模型空间) 的内容以非标准输出的形式传输给 g 参数
5) 执行 g 参数,将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除,将此时的 pattern space (模型空间) 的内容传输给 N 参数
6) 执行 $! 判断当前行不是最后 1 行则为真,如果为真,执行 N 参数,将下一行的内容添加到本行内容的后面,但是两行之间存在分行符 “/n”,保存到 pattern space (模型空间),将此时的 pattern space (模型空间) 的内容以非标准输出的形式传输给 p 参数
7) 执行 p 参数,将 pattern space (模型空间) 里的内容以标准的形式显示,再将 pattern space (模型空间) 里的内容以非标准的形式传输给 D 参数
8) 执行 D 参数,删除 pattern space (模型空间) 中的第 1 行,也就是分行符 “/n” 之前的内容,并将此时 pattern space (模型空间) 里的内容传输给参数 h
9) 执行 h 参数,将 pattern space (模型空间) 中的内容拷贝到 hold space (保持空间) 中,原来的 hold space (保持空间)里的内容被清除
10) 这里的 test.txt 是要被 sed 操作的测试文件

2.8 显示包含从 2000 到 2007 点行

# sed -n '/2000/,/2007/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

(注意:test.txt 里必须要有包含 2000 内容和 2007 内容的行此命令才会生效)

2.9 显示从 2022-01-01 00:00:00 到 2022-02-22 00:00:00 的内容

# sed -n  '/2022-01-01 00:00:00/,/2022-02-22 00:00:00/p' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

(注意:test.txt 里必须要有包含 2022-01-01 00:00:00 内容和 2022-02-22 00:00:00 内容的行此命令才会生效)

2.10 显示从 2022-01-01 00:00:00 到最后的内容

# sed '/2019-01-01/,$' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

(注意:test.txt 里必须要有包含 2019-01-01 内容的行此命令才会生效)

2.11 显示总行数

# sed -n $= test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.12 以非标准输出的方式显示每 1 行是第几行,在行数后面以标准输出的方式显示行的内容,但是不显示第 1 行的内容

# sed -n '{=;1!p}' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.13 以非标准输出的方式显示每 1 行是第几行,在行数后面以标准输出的方式显示行的内容,但是不显示第 1 行的内容

# sed -n '{=;2!p}' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.14 添加行号并显示所有内容

# sed = test.txt | sed 'N;s/\n/:/'

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.15 显示奇数行

# sed -n 'p;n' test.txt


补充:
1) 执行第 1 行,执行 p 参数,将第 1 行的内容以标准输出的形式进行显示,再将第 1 行的内容以非标准输出的形式传输给 n 参数,再执行 n 参数,将第 1 行的内容以标准输出的形式进行显示 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里变为以非标准的形式进行显示),再将第 1 行的内容被第 2 行的内容覆盖,再将第 1 行的内容以标准输出的形式显示 1 遍 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里不再进行显示),再跳过第 2 行再直接执行第 3 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
2) 执行第 3 行,执行 p 参数,将第 3 行的内容以标准输出的形式进行显示,再将第 3 行的内容以非标准输出的形式传输给 n 参数,再执行 n 参数,将第 3 行的内容以标准输出的形式进行显示 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里变为以非标准的形式进行显示),再将第 3 行的内容被第 4 行的内容覆盖,再将第 1 行的内容以标准输出的形式显示 1 遍 (但是这里传输给 n 参数的内容已经是非标准的形式了,所以这里不再进行显示),再跳过第 4 行再直接执行第 5 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
3) 以此类推
4) 当执行到最后 1 行时,按照之前的逻辑,如果是奇数行则显示当前行的内容,如果是偶数行则跳过
5) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed -n '$!N;P' test.txt


补充:
1) $! 作用是判断当前行不是最后 1 行时执行后面的命令
2) 执行第 1 行,执行 $! 判断当前行不是最后 1 行则为真,第 1 行不是最后 1 行,执行 N 命令,将第 2 行的内容添加到第 1 行的内容的后面,但是第 1 行和第 2 行之间存在分行符 “/n”,再将当前行的内容以标准输出的形式传输给 P 参数,再执行 P 命令,将此时第 1 行的内容以标准输出的形式进行显示,再将分行符 “/n” 之前的所有内容 (也就是最早是第 1 行的内容) 以非标准输出的形式显示出来,并跳过第 2 行再直接执行第 3 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
3) 执行第 3 行,执行 $! 判断当前行不是最后 3 行则为真,第 3 行不是最后 1 行,执行 N 命令,将第 4 行的内容添加到第 3 行的内容的后面,但是第 3 行和第 4 行之间存在分行符 “/n”,再将当前行的内容以标准输出的形式传输给 P 参数,再执行 P 命令,将此时第 3 行的内容以标准输出的形式进行显示,再将分行符 “/n” 之前的所有内容 (也就是最早是第 3 行的内容) 以非标准输出的形式显示出来,并跳过第 3 行再直接执行第 4 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
4) 以此类推
5) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
6) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed 'n;d' test.txt


补充:
1) 执行第 1 行,执行 n 参数,将第 1 行的内容以标准输出的形式进行显示,再将第 1 行的内容被第 2 行的内容替代,再将被替代的内容传输给 d 参数,再执行 d 参数将第 2 行的内容删除掉。并跳过第 2 行直接执行第 3 行
2) 执行第 3 行,执行 n 参数,将第 3 行的内容以标准输出的形式进行显示,再将第 3 行的内容被第 4 行的内容替代,再将被替代的内容传输给 d 参数,再执行 d 参数将第 4 行的内容删除掉。并跳过第 4 行直接执行第 5 行
3) 以此类推
4) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
5) 这里的 test.txt 是要被 sed 操作的测试文件

2.16 显示偶数行

# sed -n 'n;p' test.txt


补充:
1) 执行第 1 行,执行 n 参数,将第 1 行的内容以标准输出的形式进行显示,再将第 1 行的内容被第 2 行的内容替代,再将被替代的内容传输给 p 参数,再执行 p 参数,将第 2 行的内容以标准的形式显示,再将第 2 行的内容以非标准的形式显示。并跳过第 2 行再直接执行第 3 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
2) 执行第 3 行,执行 n 参数,将第 3 行的内容以标准输出的形式进行显示,再将第 3 行的内容被第 4 行的内容替代,再将被替代的内容传输给 p 参数,再执行 p 参数,将第 4 行的内容以标准的形式显示,再将第 4 行的内容以非标准的形式显示。并跳过第 4 行再直接执行第 5 行。前面以标准输出的形式显示的内容被 -n 选项屏蔽
3) 以此类推
4) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
5) 这里的 test.txt 是要被 sed 操作的测试文件

2.17 显示所有行是第几行,行数后面跟行的内容

# sed = test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.18 显示所有行是第几行,只显示行数

# sed -n test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.19 显示包含 eternalcenter 内容的行是第几行

# sed -n '/eternalcenter/=' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.20 显示所有空行是第几行

# sed -n '/^$/=' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

2.21 合并相同的行,也就是相同行去重

# sort test.txt | sed '$!N;/^\(.*\)\n\1$/!P;D'

(
补充:
1) 执行 sort 将所有的行进行排序将相同的行排在一起,并结果输出给 sed
2) 执行第 1 行,执行 $! 判断当前行不是最后 1 行则为真,第 1 行不是最后 1 行,执行 N 参数,将第 2 行的内容添加到第 1 行的内容的后面,但是第 1 行和第 2 行之间存在分行符 “/n”,再将组合后的内容传输给 P 参数,再执行 /^(.*)\n\1$/! 判断当前行 \n 前面和后面不一样则为真,当为假时则直接不执行将内容传输给 D 参数,当为真时,执行 P 参数,先将第 1 行的内容以非标准输出的形式显示一遍,但是如果是 2 行组合在一起的话只显示第 1 行的内容,也就是只显示分行符 “/n” 之前的内容,再将第 1 行的内容以标准输出的形式传输给 D 参数,执行 D 参数,删除内容中的第 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行第 2 行,如果删除后没有内容了,则跳过第 2 行直接执行第 3 行
3) 以此类推
4) 当执行到最后 1 行时,因为已经没有下 1 行了,所以停止命令
5) 这里的 test.txt 是要被 sed 操作的测试文件
)

内容三:sed 使用 a 参数在某 1 行后面添加数据的案例

3.1 在第 2 行后面添加 1 行 eternalcenter

# sed "2a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.2 在 abc 那 1 行后面添加 1 行 eternalcenter

# sed "/abc/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.3 在 test.txt 文件里在以 a 开头的行后面添加 eternalcenter

# sed "/^a/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.4 在以 [a] 开头的行后面添加 eternalcenter

# sed "/^\[a\]/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.5 在最后 1 行后面添加 eternalcenter

# sed "$a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

3.6 在 eternalcenter 这 1 行后面添加 eternalcentre、mingyuzhu 和 zhumingyu 3 行

# sed '/eternalcenter/a eternalcentre\nmingyuzhu\nzhumingyu' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容四:sed 使用 i 参数在某 1 行前面插入数据的案例

4.1 在第 2 行前面插入 1 行 eternalcenter

# sed "2i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.2 在 abc 那 1 行前面插入 1 行 eternalcenter

# sed "/abc/i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.3 在以 a 开头的行前面插入 eternalcenter

# sed "/^a/i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.4 在以 [a] 开头的行前面插入 eternalcenter

# sed "/^\[a\]/i eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

4.5 在最后 1 行后面添加 eternalcenter

# sed "$a eternalcenter" test.txt

或者:

# sed "/$/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容五:sed 使用 c 参数替换某些行数据的案例

5.1 将第 2 行替换成 eternalcenter

# sed "2c\ eternalcenter" test.txt

或者:

# sed "2ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.2 将 abc 那 1 行替换成 eternalcenter

# sed "/abc/c\ eternalcenter" test.txt

或者:

# sed "/abc/ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.3 将以 a 开头的那 1 行替换成 eternalcenter

# sed "/^a/c\ eternalcenter" test.txt

或者:

# sed "/^a/ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.4 将以 [a] 开头的那 1 行替换成 eternalcenter

# sed "/^\[a\]/c\ eternalcenter" test.txt

或者:

# sed "/^\[a\]/ceternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

5.5 将以 eternalcentre 开头的那 1 行替换成 eternalcenter ALL=(ALL) NOPASSWD: ALL

# sed "/^eternalcentre/c\ eternalcenter\ ALL=\(ALL\)\ NOPASSWD:\ ALL" test.txt

或者:

# sed "/^eternalcentre/c\eternalcenter\ ALL=\(ALL\)\ NOPASSWD:\ ALL" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容六:sed 使用 d 参数删除某些行的案例

6.1 删除第 2 行

# sed 2d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.2 删除包含 abc 的那 1 行

# sed /"abc"/d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.3 删除以 a 开头的那 1 行

# sed /"^a"/d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.4 删除以 [a] 开头的那 1 行

# sed /"^\[a\]"/d test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.5 删除所有被注释掉的行

# sed '/^#/d' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

6.6 删除第 2 行到第 4 行

# sed '2,4d' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容七:sed 使用 s 或者 y 参数替换某些行某些数据的案例

7.1 将所有行的第一个 eternalcentre 换成 eternalcenter

# sed 's/eternalcentre/eternalcneter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.2 将所有行的所有 eternalcentre 换成 eternalcenter

# sed 's/eternalcentre/eternalcneter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.3 将包含 eternalcentre 的行换成 eternalcenter

# sed 's/.*eternalcentre.*/eternalcneter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.4 将第 3 行的第 2 个 eternalcentre 换成 eternalcenter

# sed '3s/eternalcentre/eternalcenter/2' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.5 在所有行前面添加 eternalcenter

# sed 's/^/eternalcenter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

或者:

# sed 's/^/eternalcenter&/g test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.6 在所有行后面添加 eternalcenter

# sed 's/$/eternalcenter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

或者:

# s/$/&eternalcenter/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.7 将第 2 行替换成 eternalcenter

# sed '2s/.*/eternalcenter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.8 将最后 1 行替换成 eternalcenter

# sed '$s/.*/eternalcenter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.9 将第 2 到第 3 行替换成 eternalcenter

# sed '2,3s/.*/eternalcenter/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.10 将 eternalcenter 前面的数据和后面的数据对调位置

# sed "s/^\(.*\)\(eternalcenter\)\(.*\)$/\3\2\1/" test.txt

或者:

# sed -r "s/(.*)(eternalcenter)(.*)/\3\2\1/" test.txt

或者:

# sed -r "s/(.*)((eternal)(center))(.*)/\5\2\1/" test.txt

(补充:这里以 (.*) 是 1,((eternal)(center)) 是 2,(eternal) 是 3,(center) 是 4,(.*) 是 5 为例,这里的 test.txt 是要被 sed 操作的测试文件)

7.11 所有行前后字符串互调

# sed -r 's/.*/&\n/g;:a;s/(.*)(.)\n(.*)/\1\n\3\2/g;ta;s/^\n//g' test.txt


补充:
1) 执行 s/.*/&\n/g 在每行行尾添加换行符 “\n”
2) 执行 a 参数和 ta 参数,将从 :a 到 ta 之间的内容以后面的操作作为循环条件只要还能继续执行就一直循环,每次执行 s/(.*)(.)\n(.*)/\1\n\3\2/g,将此时所有行换行符 “\n” 之前的内容里最后一个字母移动到所有行换行符 “\n” 之后到内容里最后一个位置
3) 执行 s/^\n//g 删除所有行的换行符 “\n”
4) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed -r 's/.*/&\n/g;:b;s/(.*)(.)\n(.*)/\1\n\3\2/g;tb;s/^\n//g' test.txt


补充:
1) 执行 s/.*/&\n/g 在每行行尾添加换行符 “\n”
2) 执行 b 参数和 tb 参数,将从 :b 到 tb 之间的内容以后面的操作作为循环条件只要还能继续执行就一直循环,每次执行 s/(.*)(.)\n(.*)/\1\n\3\2/g,将此时所有行换行符 “\n” 之前的内容里最后一个字母移动到所有行换行符 “\n” 之后到内容里最后一个位置
3) 执行 s/^\n//g 删除所有行的换行符 “\n”
4) 这里的 test.txt 是要被 sed 操作的测试文件

7.12 删除每行的第 1 个字符和最后 1 个字符

# sed 's/.//1;s/.$//' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.13 删除每行的第 2 个字符和最后 1 个字符

# sed 's/.//2;s/.$//' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.14 删除所有行的数字和空格

# sed -r 's/[0-9]//g;s/^( )+//g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.15 删除 1 行不是最后 1 行包含 eternalcenter 的行

# sed '/eternalcenter/N;s/.*\n//' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.16 将所有的大写字母都添加括号

# sed 's/[A-Z]/(&)/g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.17 在第 7 行和第 9 行前面添加 “#”

# sed '7,9s/^/#/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.18 删除第 1 个空格

# sed -r 's/( )(.*)/\2/'

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.19 在以打写字母开头,中间是小写字母,以数字结尾的行里在小写字母和数字之间插入 ok

# sed -r 's/^([A-Z]{1,})([a-z]{1,})([0-9]{1,})$/\1\2ok\3/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.20 在以打写字母开头,中间是小写字母,以数字结尾的行里在小写字母和数字之间插入 ok,并将数字替换到最前面

# sed -r 's/^([A-Z]{1,})([a-z]{1,})([0-9]{1,})$/\3 ok \1\2/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.21 删除 2022-01-01 字符里的横杠 “-”

# sed -r 's/([0-9]{1,})\-([0-9]{1,})\-([0-9]{1,})/\1\2\3/' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.22 将日期的年月日以空格分开

# echo 20220222 | sed -r 's/(....)(..)(..)/\1 \2 \3/'

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.23 合并上下行

# sed '$!N;s/\n/ /' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.24 将以反斜杠号 “\” 结尾的行与下 1 行合并在一起并以空格进行分隔 (只合并一次)

# sed '/\\$/N;s/\\\n/ /' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.25 将以反斜杠号 “\” 结尾的行与下 1 行合并在一起并以空格进行分隔 (能合并多少次就合并多少次)

# sed -e :a -e '/\\$/N;s/\\\n/ /; ta' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

7.26 若某行以 = 开头则合并到上 1 行并将等于号 “=” 替换成空格

# sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' num.txt 


补充:
1) 执行 :a 参数和 ta 参数,将从 :a 到 ta 之间的内容以后面的操作作为循环条件只要还能继续执行就一直循环,每次执行 $!N;s/\n=/ /,当不是最后 1 行时,将下 1 行的内容添加到本行后面,但是本行的内容和下 1 行的内容之间依旧存在分行符 “/n”,如果此时存在 \n=,则将其替换成空格,再将最后的结果以非标准输出的方式传输给 P 参数,执行 P 参数,将分行符 “/n” 之前的所有内容 (也就是最初此行的内容) 以非标准输出的形式显示,再将此时的所有内容以非标准输出的形式传输给 D 参数,执行 D 参数,删除前 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行,否则跳过往下第 1 行接着执行往下第 2 行
2) 以此类推
3) 执行 s/^\n//g 删除所有行的换行符 “\n”
4) 这里的 test.txt 是要被 sed 操作的测试文件

7.27 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是 1 个 5 个字符长度的字节)

# awk '{for(i=1;i<=NF;i++){if(i in arr){arr[i]=arr[i]" "$i}else{arr[i]=$i}}}END{for(i=1;i<=NF;i++){print arr[i]}}' test.txt | sort | sed -e :a -e '$!N;/^\(.....\).*\n\1.*/s/^\(.*\)\(\n\)\(.....\)\(.*\)/\1\4/g; ta'

(补充:这里的 test.txt 是要被 awk 操作的测试文件)

7.28 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是以 .com 结尾)

# awk '{for(i=1;i<=NF;i++){if(i in arr){arr[i]=arr[i]" "$i}else{arr[i]=$i}}}END{for(i=1;i<=NF;i++){print arr[i]}}' test.txt | sort | sed -e :a -e '$!N;/^\(.*\.com\).*\n\1.*/s/^\(.*\)\(\n\)\(.*\.com\)\(.*\)/\1\4/g; ta'

(补充:这里的 test.txt 是要被 awk 操作的测试文件)

7.29 行列转换,并且将第 1 行相同的列,行列转换以后合并,也就是行列转换以后没有第 1 列相互重复的行 (指定 1 列是以空格 “ ” 结尾)

# > awk '{for(i=1;i<=NF;i++){if(i in arr){arr[i]=arr[i]" "$i}else{arr[i]=$i}}}END{for(i=1;i<=NF;i++){print arr[i]}}' test.txt | sort | sed -e :a -e '$!N;/^\(.*\ \).*\n\1.*/s/^\(.*\)\(\n\)\(.*\ \)\(.*\)/\1 \4/g; ta'

(补充:这里的 test.txt 是要被 awk 操作的测试文件)

内容八:sed 使用 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数第案例

8.1 sed 的工作原理

1) 从第 1 行开始 1 行 1 行地读取文件里的内容
2) 每读取 1 行就将内容存入到 pattern space (模型空间) 里面,pattern space (模型空间) 里的内容默认会自动显示出来
3) 在 pattern space (模型空间) 中执行 sed 命令
4) 再显示 pattern space (模型空间) 中的内容然后将其清空
5) 之后重复以上操作再开始读取文件里的下 1 行
6) pattern space (模型空间) 里的内容可以存储到 hold space (保持空间) 里面


补充:
1) pattern space (模型空间) 相当于处理内容的流水线
2) hold space (保持空间) 相当于暂时存储内容的仓库

8.2 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的讲解

8.2.1 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的作用简介

1) g 将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除
2) G 将 hold space (保持空间) 中的内容 append (添加) 到 pattern space (模型空间) 分行符 “/n” 后
3) h 将 pattern space (模型空间) 中的内容拷贝到 hold space (保持空间) 中,原来的 hold space (保持空间)里的内容被清除
4) H 将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后
5) d 删除 pattern space (模型空间) 中的所有行,并执行下 1 行
6) D 删除 pattern space (模型空间) 中的第 1 行,也就是分行符 “/n” 之前的内容,如果删除后还有内容,则以此内容作为新的 1 行往下执行

8.2.2 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的功能示意图
P H     P H     P H
1    h  1 1  d    1

P H     P H     P H     P H
2 1  G  2 1  H  2 1  d    1
        1       1 2       2
                  1       1

P H     P H     P H
3 2  G  3 2  h  3 3
  1     2 1     2 2
        1       1 1

P H     P H
3 2  g  2 2
  1     1 1


补充:
1) 这里的 P 指的是 pattern space (模型空间)
2) 这里的 H 指的是 hold space (保持空间)
3) h 其实就是清空现在粘贴板里的内容然后重新复制
4) H 其实就是不清空现在粘贴板里的内容然后再再原来粘贴版的内容基础上再添加复制
5) g 其实就是替换粘贴
6) G 其实就是添加粘贴

8.3 h 参数、H 参数、g 参数、G 参数、d 参数、D 参数的使用案例

8.3.1 将第 1 行的数据添加到第 3 行后面
# sed -e '1h' -e '3G' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.2 将第 1 行的数据替换第 3 行
# sed -e '1h' -e '3g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.3 将第 1 行和第 2 行的数据添加到第 3 行后面
# sed -e '1h' -e '2H' -e '3G' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.4 将第 1 行和第 2 行的数据替换第 3 行
# sed -e '1h' -e '2H' -e '3g' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.5 将第 1 个以 a 开头的行的数据添加到第 3 行后面
# sed -e '/^a/h' -e '3G' 1.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.6 将第 1 个和第 2 个以 a 开头的行的数据添加到第 3 行后面
# sed -e '/^a/h' -e'/^a/H' -e '3G' 1.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

8.3.7 将 eternalcenter 的 eternal 和 center 以空格分开
# echo "eternalcenter" | sed -r 'H;s/(.{7}).*/\1/;x;s/.*(.{6})$/\1/;x;G;s/\n/ /'

(
1) 执行 H 参数,将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后,并将此时的 pattern space (模型空间) 传输给 s 参数
2) 执行 s/(.{7})./\1/,将 pattern space (模型空间) 中的内容只保留前 7 个字符,并将此时的 pattern space (模型空间) 传输给 x 参数 3) 执行 x 参数,将 hold space (保持空间) 和 pattern space (模型空间) 内容互换,,并将此时的 pattern space (模型空间) 传输给 s 参数 4) 执行 s/.(.{6})$/\1/,将 pattern space (模型空间) 中的内容只保留后 6 个字符,并将此时的 pattern space (模型空间) 传输给 x 参数
5) 执行 x 参数,将 hold space (保持空间) 和 pattern space (模型空间) 内容互换,,并将此时的 pattern space (模型空间) 传输给 G 参数
6) 执行 G 参数,将 hold space (保持空间) 中的内容 append (添加) 到 pattern space (模型空间) 分行符 “/n” 后,并将此时的 pattern space (模型空间) 传输给 s 参数
7) 执行 s/(.{7}).*/\1/,将 pattern space (模型空间) 中的内容删除换行符 “\n”
)

8.3.8 显示九九乘法表
# seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'


补充:
1) 执行 seq 9 命令,第 1 行输出 1,第 2 行输出 2,以此类推直到第 9 行,并将结果传输给 sed 命令
2) 执行 sed 的 H 参数,将 pattern space (模型空间) 中的内容 append (添加) 到 hold space (保持空间) 分行符 “/n” 后,并将此时的 pattern space (模型空间) 传输给 g 参数。当执行到第 1 行时,添加到 hold space (保持空间) 是 1,hold space (保持空间) 里的值是 \n1,当时执行到第 2 行时,添加到 hold space (保持空间) 是 2,hold space (保持空间) 里的值是 \n1\n2,依次类推
3) 执行 sed 的 g 参数,将 hold space (保持空间) 中的内容拷贝到 pattern space (模型空间) 中,原来 pattern space (模型空间) 里的内容被清除。当执行到第 1 行时,hold space (保持空间)里的值是 \n1,pattern space (模型空间) 里的值将是 \n1,显示的结果也会是 1,当执行到第 2 行时,hold space (保持空间)里的值是 \n1\n2,pattern space (模型空间) 里的值将是 \n1\n2,显示的结果也会是 \n1\n2,依次类推,并将结果传输给命令 awk
3) awk,将多行视为 1 行,会执行从 1 到此行列数次循环,变量 i 初始时的值为 1,每执行 1 次则变量 i 到值会加 1,每次循环时会显示:“此时变量 i 的值”*“此行的列数”=“此时变量 i 的值和此行的列数的乘积““当此时变量 i 的值等于此行的列数时则换行,否则的话则显示制表符的空格长度”。当执行到第 1 行时显示的是 1×1=1,当执行到第 2 行时显示的是 1×2=2 2×2=4,以此类推

内容九:sed 一次匹配多个参数的案例

在 abc 和 bbb 那两行后面添加 1 行 eternalcenter

# sed -e "/abc/a eternalcenter" -e "/^bbb/a eternalcenter" test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容十:sed r 参数和 w 参数读取和写入文件

10.1 将 test2.txt 文件里的内容添加到 test1.txt 文件里内容的第3 行后面

# sed '3r test2.txt' test1.txt

(补充:这里的 test1.txt 和 test2.txt 是要被 sed 操作的测试文件)

10.2 将 test1.txt 文件里内容的第三行保存到 test2.txt 中

# sed '3w test2.txt' test1.txt

(补充:这里的 test1.txt 和 test2.txt 是要被 sed 操作的测试文件)

内容十一:sed q 参数退出当前执行的内容

11.1 执行完第 5 行后退出

# sed '5 q' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

11.2 执行完包含 eternalcenter 的行后退出

# sed '/eternalcenter/ q' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

11.3 执行完第 3 行后退出,并将退出代码设置为 3

# sed '3 q 3' test.txt

(补充:这里的 test.txt 是要被 sed 操作的测试文件)

内容十二:sed b 参数和 t 参数设置标签分支

12.1 如果某行不包含 eternalcenter 则将此行中内容的 0 换成 1,否则将此行中内容的 0 换成 2

# sed '{/eternalcenter/b lable;s/0/1/;:lable}' test.txt


补充:
1) 在这里 lable 是标签
2) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed '/eternalcenter/ba;s/0/1/;b;:a' test.txt


补充:
1) 在这里 a 是标签
2) 这里的 test.txt 是要被 sed 操作的测试文件

12.2 如果某行包含 eternalcenter 则将此行中内容的 0 换成 1,否则将此行中内容的 0 换成 2

# sed '/eternalcenter/s/0/1/;t;s/0/2/' test.txt


补充:
1) 在这里的标签省略了,所以标签分支会一直到头部
2) 这里的 test.txt 是要被 sed 操作的测试文件

或者:

# sed -e :a -e '/eternalcenter/s/0/1/;ta;s/0/2/' test.txt


补充:
1) 在这里 a 是标签
2) 这里的 test.txt 是要被 sed 操作的测试文件

[命令] Linux 命令 grep (显示文本的行)

案例一:grep 使用 perl 正则表达式匹配

# grep -P '^root' /etc/passwd

或者:

# grep --perl-regexp '^root' /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中开头为 root 的行为例)

案例二:grep 使用正则表达式匹配

# grep -e '^root' /etc/passwd

或者:

# grep --regexp=PATTERN '^root' /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中开头为 root 的行为例)

案例三:grep 使用扩展正则表达式匹配

# grep -E '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# grep --extended-regexp '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行为例)

案例四:grep 显示行号

4.1 显示某些关键字所在行行号

# egrep -n '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --line-number '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --line-buffered '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并显示行号为例)

4.2 显示哪些行号是空行

# egrep -n ^$ /etc/resolv.conf

或者:

# egrep --line-number ^$ /etc/resolv.conf

或者:

# egrep --line-buffered ^$ /etc/resolv.conf

(补充:这里以匹配 /etc/resolv.conf 里的空行并显示行号为例)

案例五:grep 取反匹配

5.1 取反不匹配某些关键字

# egrep -v '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --invert-match '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里不含有 IP 地址的行并显示行号为例)

5.2 取反不显示空行

# egrep -v ^$ /etc/resolve.conf

或者:

# egrep --invert-match ^$ /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不为空的行为例)

5.3 取反不显示以井号 “#” 开头的行

# grep '^[^#]' /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不以井号 “#” 开头的行为例)

5.4 取反不显示以井号 “#” 或空格 “ ” 开头的行

# grep '^[^#| ]' /etc/resolve.conf

(补充:这里以匹配 /etc/resolve.conf 文件里不以井号 “#” 和空格 “ ” 开头的行为例)

案例六:grep 只显示匹配的部分

# egrep -o '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --only-matching '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 里的 IP 地址为例)

(注意:这里匹配后只显示 IP 地址,而不显示 IP 地址所在行里的其他内容)

案例七:grep 匹配时忽略大小写

# egrep -i '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --ignore-case '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并忽略大小写为例)

案例八:grep 统计匹配成功次数

# egrep -c '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

或者:

# egrep --count '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行的数量为例)

案例九:grep 将匹配成功的部分自动添加颜色

# egrep --color=auto '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并自动添加颜色为例)

案例十:grep 将匹配成功的部分自动取消颜色

# egrep --color=no '([1-9][0-9]{0,2}\.){3}[1-9][0-9]{0,2}' /etc/sysconfig/network-scripts/ifcfg-ens192  

(补充:这里以匹配 /etc/sysconfig/network-scripts/ifcfg-ens192 文件里含有 IP 地址的行并取消自动添加颜色为例)

案例十一:grep 一次匹配多个参数

# grep -e root -e zhumingyu /etc/passwd

(补充:这里以匹配 /etc/passwd 文件中包含 root 或 zhumingyu 的行为例)

案例十二:grep 显示匹配内容附近的内容

12.1 显示匹配内容的前 10 行

# grep -a 10 eternalcenter test.txt

或者:

# grep --text 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其前 10 行为例)

12.2 显示匹配内容的后 10 行

# grep -b 10 eternalcenter test.txt

或者:

# grep --byte-offset 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其后 10 行为例)

12.3 显示匹配内容的前后 10 行

# grep -a -b 10 eternalcenter test.txt

或者:

# grep --text --byte-offset 10 eternalcenter test.txt

(补充:这里以匹配 test.txt 文件中包含 eternalcenter 的行并显示其前后 10 行为例)

案例十三:grep 安静匹配

# grep -q root /etc/passwd

或者:

# grep --quiet root /etc/passwd

或者:

# grep --silent root /etc/passwd
# echo $?
0


补充:
1) 这种方法主要用于在 Shell 脚本中,随后使用 if 判断判断匹配是否成功
2) 这里以匹配 /etc/passwd 中是否包含 root 用户为例