GVKun编程网logo

Perl、Python、AWK 和 sed 有什么区别?(sed grep awk区别)

1

对于想了解Perl、Python、AWK和sed有什么区别?的读者,本文将提供新的信息,我们将详细介绍sedgrepawk区别,并且为您提供关于9.6awk(上)9.7awk(下)、AWK/sed-在

对于想了解Perl、Python、AWK 和 sed 有什么区别?的读者,本文将提供新的信息,我们将详细介绍sed grep awk区别,并且为您提供关于9.6 awk(上) 9.7 awk(下)、AWK / sed-在小于特定值的数字之前在文本文件中写入文本、awk / sed-在比赛后打印第n个值、awk / sed:在特定块号的最后一行之前插入文件内容的有价值信息。

本文目录一览:

Perl、Python、AWK 和 sed 有什么区别?(sed grep awk区别)

Perl、Python、AWK 和 sed 有什么区别?(sed grep awk区别)

它们之间的主要区别是什么?在哪些典型场景中使用每种语言更好?

答案1

小编典典

按出现顺序,语言是sed, awk, perl, python.

sed程序是一个流编辑器,旨在将脚本中的操作应用于输入文件的每一行(或更一般地说,应用于指定的行范围)。它的语言基于edUnix
编辑器,虽然它有条件等,但很难用于复杂的任务。你可以用它创造小奇迹——但要付出你头上的头发的代价。但是,在尝试其职权范围内的任务时,它可能是最快的程序。(它具有讨论的程序中最不强大的正则表达式
- 适用于许多目的,但肯定不是 PCRE - Perl-Compatible Regular Expressions)

awk程序(名称来自其作者的首字母 - Aho、Weinberger 和
Kernighan)最初是用于格式化报告的工具。它可以用作增强剂sed;在其最新版本中,它在计算上是完整的。它使用了一个有趣的想法——该程序基于“模式匹配”和“模式匹配时采取的操作”。这些模式相当强大(扩展正则表达式)。动作的语言类似于
C。其主要特点之一awk是它自动将输入拆分为记录,并将每条记录拆分为字段。

Perl 部分是作为 awk-killer 和 sed-killer
编写的。它提供的两个程序是a2ps2p用于将awk脚本和sed脚本转换为 Perl。Perl 是最早的下一代脚本语言之一(Tcl/Tk
可能占据主导地位)。它具有强大的集成正则表达式处理和更强大的语言。它提供对几乎所有系统调用的访问,并具有 CPAN
模块的可扩展性。(两者都awk不可sed扩展。)Perl 的座右铭之一是“TMTOWTDI - 有不止一种方法可以做到”(发音为“tim-
toady”)。Perl 有“对象”,但它更像是一个附加组件,而不是语言的基本部分。

Python 是最后编写的,可能部分是对 Perl 的反应。它有一些有趣的句法思想(缩进表示级别 - 没有大括号或等价物)。它比 Perl
更基本面向对象;它和 Perl 一样可扩展。

好的 - 什么时候使用每个?

  • Sed - 当您需要对文件进行简单的文本转换时。
  • awk - 当您只需要简单的格式化和汇总或数据转换时。
  • Perl - 几乎适用于任何任务,尤其是当任务需要复杂的正则表达式时。
  • Python - 用于您可以使用 Perl 的相同任务。

我不知道 Perl 可以做 Python 做不到的任何事情,反之亦然。两者之间的选择将取决于其他因素。我在 Python 出现之前就学习了
Perl,所以我倾向于使用它。Python 具有较少的附加语法,并且通常更易于学习。Perl 6,当它可用时,将是一个引人入胜的发展。

(请注意,Perl 和 Python 的“概述”尤其是非常不完整;整本书都可以写在这个主题上。)

9.6 awk(上) 9.7 awk(下)

9.6 awk(上) 9.7 awk(下)

9.6 awk(上)

awk,支持分段匹配,awk并不会更改文件的内容,只会在屏幕上显示运行结果而已
匹配字符串的时候 必须加上""
创建测试数据文件

[root@aminglinux-02 tmp]# cp /etc/passwd ./test.txt
[root@aminglinux-02 tmp]# cat test.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
chrony:x:997:995::/var/lib/chrony:/sbin/nologin
  • 指定段的分隔符

-F '':'',指定分隔符为 :,以便之后容易区分,命令是对第几段进行操作

指定 分割符为 : 冒号,打印第一段,第一段用 $1 表示

[root@aminglinux-02 tmp]# awk -F '':'' ''{print $1}'' test.txt
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-bus-proxy
systemd-network
dbus
polkitd
tss
postfix
sshd
chrony

打印所有段,$0 表示所有的段

awk -F '':'' ''{print $0}'' test.txt
awk ''{print $0}'' test.txt

-F 选项;如果没有去指定分隔符 ,那么将模式使用空白、空格为分隔符

[root@aminglinux-02 tmp]# cat 1.txt
1 2
aa bb
dd ee
[root@aminglinux-02 tmp]# awk ''{print $1}'' 1.txt
1
aa
dd

打印test.txt文本下的1、3、5段,因为内容太长,所以我用了head只显示10行

[root@aminglinux-02 tmp]# awk -F '':'' ''{print $1,$3,$5}'' test.txt |head
root 0 root
bin 1 bin
daemon 2 daemon
adm 3 adm
lp 4 lp
sync 5 sync
shutdown 6 shutdown
halt 7 halt
mail 8 mail
operator 11 operator
[root@aminglinux-02 tmp]# cat -n test.txt |head
     1    root:x:0:0:root:/root:/bin/bash
     2    bin:x:1:1:bin:/bin:/sbin/nologin
     3    daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4    adm:x:3:4:adm:/var/adm:/sbin/nologin
     5    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     6    sync:x:5:0:sync:/sbin:/bin/sync
     7    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     8    halt:x:7:0:halt:/sbin:/sbin/halt
     9    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10    operator:x:11:0:operator:/root:/sbin/nologin
  • 打印信息分隔

对打印出的信息,以 # 进行分隔

awk -F '':'' ''{print $1"#"$2"#"$3}''
[root@aminglinux-02 tmp]# awk -F '':'' ''{print $1"#"$2"#"$3}'' test.txt |head
root#x#0
bin#x#1
daemon#x#2
adm#x#3
lp#x#4
sync#x#5
shutdown#x#6
halt#x#7
mail#x#8
operator#x#11
  • 关键字匹配

把包含 oo 的行,打印出来

awk ''/oo/'' test.txt
[root@aminglinux-02 tmp]# awk ''/oo/'' test.txt
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

匹配第一段,为oo的行,匹配的时候,支持正则,而且不需要脱义特殊符号,还支持多个条件同时匹配

awk -F '':'' ''$1 ~/oo/'' test.txt
[root@aminglinux-02 tmp]# awk -F '':'' ''$1 ~/oo/'' test.txt
root:x:0:0:root:/root:/bin/bash

多个关键词同时匹配,并打印出所在行的某个段
匹配root的,打印第一段、第三段信息;匹配user的打印第一段,第三段,第四段的信息

[root@aminglinux-02 tmp]# awk -F '':'' ''/root/ {print $1,$3} /user/ {print $1,$3,$4}'' test.txt
root 0
operator 11
tss 59 59
user1 1000 1000
user2 1001 1001
user3 1002 1002
user4 1003 1003
user5 1004 1004
  • 逻辑运算方式匹配关键字
awk -F '':'' ''$3==0'' test.txt 等同于 awk -F '':'' ''$3==0 {print $0} '' test.txt

匹配逻辑运算方式是 $3==1000 和 $3=="1000" 是不一样的。加了双引号的数字,匹配运算方式是以 变量 LC_ALL=C 的方式进行运算,所以匹配到的结果差异很

数学运算方式匹配

[root@aminglinux-02 tmp]# awk -F '':'' ''$3>=1000'' test.txt
user1:x:1000:1000::/home/user1:/bin/bash
user2:x:1001:1001::/home/user2:/bin/bash
user3:x:1002:1002::/home/user3:/bin/bash
user4:x:1003:1003::/home/user4:/bin/bash
user5:x:1004:1004::/home/user5:/bin/bash

逻辑运算方式匹配

[root@aminglinux-02 tmp]# awk -F '':'' ''$3>="1000"'' test.txt
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
chrony:x:997:995::/var/lib/chrony:/sbin/nologin
user1:x:1000:1000::/home/user1:/bin/bash
user2:x:1001:1001::/home/user2:/bin/bash
user3:x:1002:1002::/home/user3:/bin/bash
user4:x:1003:1003::/home/user4:/bin/bash
user5:x:1004:1004::/home/user5:/bin/bash
  • 不等于的匹配方式

test.txt文件下,第7段不等于 /sbin/nologin 的 打印整行

awk -F '':'' ''$7!="/sbin/nologin"'' test.txt
[root@aminglinux-02 tmp]# awk -F '':'' ''$7!="/sbin/nologin"'' test.txt
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
user1:x:1000:1000::/home/user1:/bin/bash
user2:x:1001:1001::/home/user2:/bin/bash
user3:x:1002:1002::/home/user3:/bin/bash
user4:x:1003:1003::/home/user4:/bin/bash
user5:x:1004:1004::/home/user5:/bin/bash

9.7 awk(下)

承接上一节,逻辑运算方式匹配

两个字段进行比较

awk -F '':'' ''$3<$4'' test.txt
awk -F '':'' ''$3>5 && $3<7'' /etc/passwd
  • 判断类查找匹配
    && 且

数学运算

[root@aminglinux-02 tmp]# awk -F '':'' ''$3>5 && $3<7'' /etc/passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

逻辑运算

[root@aminglinux-02 tmp]# awk -F '':'' ''$3>"5" && $3<"7"'' /etc/passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin

|| 或

匹配第三段大于1000的 或者 第七段包含 bash
awk -F '':'' ''

  • 定义变量查找
    OFS变量
    OFS=# 定义 输出的时候以 # 作为分隔符
awk -F '':'' ''{OFS="#"} $3>1000 || $7 ~ /bash/'' {print $1,$3,$7}'' test.txt
[root@aminglinux-02 tmp]# awk -F '':'' ''{OFS="#"} $3>1000 || $7 ~ /bash/ {print $1,$3,$7}'' test.txt
root#0#/bin/bash
user1#1000#/bin/bash
user2#1001#/bin/bash
user3#1002#/bin/bash
user4#1003#/bin/bash
user5#1004#/bin/bash
  • 规范写法

=={OFS="#"} $3>1000 {print $1,$2,$3,$4}这一段中的 $3>1000 规范写法是 if ($3>1000)==

awk -F '':'' ''{OFS="#"} {if ($3>1000) {print $1,$2,$3,$4}}'' test.txt 等同于 awk -F '':'' ''{OFS="#"} $3>1000 {print $1,$2,$3,$4}'' test.txt

[root@aminglinux-02 tmp]# awk -F '':'' ''{OFS="#"} {if ($3>1000) {print $1,$2,$3,$4}}'' test.txt
user2#x#1001#1001
user3#x#1002#1002
user4#x#1003#1003
user5#x#1004#1004
[root@aminglinux-02 tmp]# awk -F '':'' ''{OFS="#"} $3>1000 {print $1,$2,$3,$4}'' test.txt
user2#x#1001#1001
user3#x#1002#1002
user4#x#1003#1003
user5#x#1004#1004

NR 变量,可以作为判断条件
显示所有行的行号

awk -F '':'' ''{print NR":"$0}'' test.txt

判断用法
NR数小于等于10行,且 每行的第一段包含root 或 sync 的行

awk -F '':'' ''NR<=10 && $1 ~ /root|sync/'' test.txt
[root@aminglinux-02 tmp]# awk -F '':'' ''NR<=10 && $1 ~ /root|sync/'' test.txt
rootx:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync

NF 变量,可以作为判断条件
显示所有行的段数

awk -F '':'' ''{print NF":"$0}'' test.txt
[root@aminglinux-02 tmp]# awk -F '':'' ''{print NF":"$0}'' test.txt
6:rootx:0:0:root:/root:/bin/bash
7:bin:x:1:1:bin:/bin:/sbin/nologin
7:daemon:x:2:2:daemon:/sbin:/sbin/nologin
7:adm:x:3:4:adm:/var/adm:/sbin/nologin
7:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
7:halt:x:7:0:halt:/sbin:/sbin/halt
7:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
7:operator:x:11:0:operator:/root:/sbin/nologin
7:games:x:12:100:games:/usr/games:/sbin/nologin
7:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
7:nobody:x:99:99:Nobody:/:/sbin/nologin
7:systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
7:systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
7:dbus:x:81:81:System message bus:/:/sbin/nologin
7:polkitd:x:998:996:User for polkitd:/:/sbin/nologin
7:tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
7:postfix:x:89:89::/var/spool/postfix:/sbin/nologin
7:sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
7:chrony:x:997:995::/var/lib/chrony:/sbin/nologin
7:user1:x:1000:1000::/home/user1:/bin/bash
7:user2:x:1001:1001::/home/user2:/bin/bash
7:user3:x:1002:1002::/home/user3:/bin/bash
7:user4:x:1003:1003::/home/user4:/bin/bash
7:user5:x:1004:1004::/home/user5:/bin/bash
  • 判断用法
    NF等于6段,且 每行的第一段包含root 或 sync 的行
awk -F '':'' ''NF==6 && $1 ~ /root|sync/'' test.txt
[root@aminglinux-02 tmp]# awk -F '':'' ''NF==6 && $1 ~ /root|sync/'' test.txt
rootx:0:0:root:/root:/bin/bash
  • 赋值
    显示/etc/passwd 的前三行,把运行结果丢给awk,awk 对之前的结果 实行 对前三的第一段赋值为 root
head -n 3 /etc/passwd |awk -F '':'' ''$1="root"''
[root@aminglinux-02 tmp]# head -n 3 /etc/passwd |awk -F '':'' ''$1="root"''
root x 0 0 root /root /bin/bash
root x 1 1 bin /bin /sbin/nologin
root x 2 2 daemon /sbin /sbin/nologin
  • 求值

tot为一个值,运算的时候是循环运算的,但是中间加了一个 END 表示运算结束,然后打印出tot的值;tot值初始为0,一次运算加上第三段的值以后开始变化,一直到END结束
下面这条命令,就是求test.txt 文件里面 第三段的和值

awk -F '':'' ''{(tot=tot+$3)}; END {print tot}'' test.txt

AWK / sed-在小于特定值的数字之前在文本文件中写入文本

AWK / sed-在小于特定值的数字之前在文本文件中写入文本

使用显示的示例,请您尝试尝试以下操作。

awk '
/^\[/{ next }
{
  for(i=1;i<=NF;i++){
    if($i>=1 && $i<=58050){
      tempfirstGroup=(tempfirstGroup?tempfirstGroup OFS:"")$i
    }
    if($i>=58051 && $i<=116100){
      tempsecondGroup=(tempsecondGroup?tempsecondGroup OFS:"")$i
    }
  }
  if(tempfirstGroup){
      firstGroup=(firstGroup?firstGroup ORS:"")tempfirstGroup
  }
  if(tempsecondGroup){
      secondGroup=(secondGroup?secondGroup ORS:"") tempsecondGroup
  }
  tempsecondGroup=tempfirstGroup=""
}
END{
  print "[  Index 1  ]" ORS firstGroup ORS "[  Index 2  ]" ORS secondGroup
}
' Input_file

输出如下。

[  Index 1  ]
1628 5704
32801
[  Index 2  ]
61605
71508 90612
102606

awk / sed-在比赛后打印第n个值

awk / sed-在比赛后打印第n个值

使用GNU awk for FPAT轻松识别字段,然后创建一个数组(下面的f[])以将字段名称映射到它们的值,您可以通过名称来引用所需的值:

$ awk -v FPAT='[[:alnum:]_]+|"[^"]*"' '
    { gsub(/^"|"$/,"",$2); f[$1]=$2 }
    /^}/ && (f["variable"] == "account_id") { print f["default"] }
' file
0987654321

通过这种方法,测试任意内容并以任意顺序打印任意内容非常简单,例如:

$ awk -v FPAT='[[:alnum:]_]+|"[^"]*"' -v OFS=',' '
    { gsub(/^"|"$/,$2); f[$1]=$2 }
    /^}/ && ( (f["variable"] == "account_id") || (f["description"] ~ /new/) ) {
        print f["description"],f["default"]
    }
' file
mount point for new device,xvdb
device name for new drive,nvme1n1
Account number,0987654321
,

给出:

$ cat file
variable "vm_ami" {
  type        = string
  description = "ami image id used for setting up the vm"
  default     = "ami-5157cd3f"
}
variable "vm_mount_name" {
  type        = string
  description = "mount point for new device"
  default     = "xvdb"
  #default     = "xvdb"
}
variable "vm_device_name" {
  type        = string
  description = "device name for new drive"
  default     = "xvdb"
  #default     = "nvme1n1"
}
variable "elb_account_id" {
  type        = string
  description = "account id for elb"
  default     = "01234567890"
}
variable "account_id" {
  type        = string
  description = "Account number"
  default     = "0987654321"
}

您可以使用Perl以一个字符串读取文件,并使用multi-line regex来解析块:

perl -0777 -ne 'while (/^variable\h+"([^"]+)"([^}]+})/gm) {
                    if ($1 eq "account_id") {
                        $2=~m/\h+default\h+[^"]+"(\d+)/;
                        print $1;
                        }
                    }' file
0987654321  

或者这个GNU awk也可以工作:

gawk  'BEGIN{ RS = "\n\\s*variable\\s" ;  FS="\n"} 
            /"account_id"/ {
                for (i=1;i<=NF; i++) {
                    if ($i~/\sdefault\s/) {
                        match($i,/^[^"]*"([^"]*)/,matches)
                        print matches[1]
                    }   
                }   
            } ' file
,

使用sed

sed -n '
    /variable "account_id"/,/^[[:blank:]]*}[[:blank:]]*$/ {
        /^[[:blank:]]*default[[:blank:]]*=[[:blank:]]*"\(.*\)".*/ {
            s//\1/p; q;
        }
    }' file

说明

假设:在输入中,只有一行与字符串variable "account_id"相匹配,而只有一行与字符串{{ 1}}在第一条匹配行和由default = "..."组成的行之间。

地址范围 }与从包含字符串/variable "account_id"/,/^[[:blank:]]*}[[:blank:]]*$/的行开始的行匹配,一直持续到仅由单个variable "account_id"组成的行, (可选)前导和/或尾随空白字符(空格或制表符)。如果您确定此行中没有空格,可以将第二个地址简化为}

正则表达式/^}$/匹配零个或多个连续的空白字符。正则表达式[[:blank:]]*与形式为^[[:blank:]]*default[[:blank:]]*=[[:blank:]]*"\(.*\)".*的整行(可能带有前导或中间的空白字符)匹配,并捕获双引号(default="...")之间的字符串。

替换命令"\(.*\)"用先前捕获的字符串(在双引号之间)替换整行,然后将其打印出来。空的正则表达式s//\1/p重复最后一个正则表达式匹配。

//命令退出q而不处理任何其他命令或输入。

,

这有点沉重,更多的是思想实验,但是该文件基本上是tcl语法,这意味着可以很容易地使用tcl创建简单的DSL来解析文件,然后提取所需的信息。

#!/usr/bin/env tclsh

# Create a new sandboxed interpreter and create functions to store
# variables and their sub-fields in an array.  Treat the sub-fields as
# commands of their own to be evaluated instead of just doing a
# straight list search for default to avoid things like
# # default = "bad" matching.
set i [interp create -safe]
interp eval $i {
    proc type {_ arg} {
        global vars varname
        set vars($varname,type) $arg
    }
    proc description {_ arg} {
        global vars varname
        set vars($varname,description) $arg
    }
    proc default {_ arg} {
        global vars varname
        set vars($varname,default) $arg
    }
    proc variable {name body} {
        global varname
        set varname $name
        eval $body
    }
}

lassign $argv filename varname
# Evaluate the file
interp invokehidden $i source $filename
# And extract the default argument of the given variable
puts [interp eval $i [list set vars($varname,default)]]

样品用量:

$ ./getvar variables.tf account_id
0987654321

awk / sed:在特定块号的最后一行之前插入文件内容

awk / sed:在特定块号的最后一行之前插入文件内容

给定是两个文件,第一个是Apacheconfiguration文件:

$ cat vhosts-ssl.conf <VirtualHost *:443> vhost 1 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 2 foobar 2 barfoo 1 foobar 1 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 3 foobar 1 barfoo 1 foobar 2 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 4 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost>

第二个文件包含应该添加到一个(可变)特定的VirtualHost块的末尾的行:

$ cat inserted.txt inserted line 1 inserted line 2

结果应该是这样的:

$ cat vhosts-ssl.conf <VirtualHost *:443> vhost 1 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 2 foobar 2 barfoo 1 foobar 1 barfoo 2 inserted line 1 inserted line 2 </VirtualHost> <VirtualHost *:443> vhost 3 foobar 1 barfoo 1 foobar 2 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 4 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost>

我尝试了以下sed的一些变化,但是这并没有诀窍:

Awk – 如何剪切一行,检查一列是否匹配,打印另一列?

awk的默认字段分隔符

用awk遍历文件列表?

AWK:有没有办法限制输出字段的宽度?

如何在列中格式化控制台输出

$ sed -e '/^<VirtualHost/{:a;n;/^</VirtualHost/!ba;r inserted.txt' -e '}' vhosts-ssl.conf

我无法弄清楚如何只select一个VirtualHost块我需要插入文件,因为我已经使用FreeBSD sed(或awk)我也得到这个错误与以前的sed命令:

$ sed -e '/^<VirtualHost/{:a;n;/^</VirtualHost/!ba;r inserted.txt' -e '}' vhosts-ssl.conf sed: 2: "} ": unused label 'a;n;/^</VirtualHost/!ba;r inserted.txt'

用GNU sed我得到这个输出:

$ gsed -e '/^<VirtualHost/{:a;n;/^</VirtualHost/!ba;r inserted.txt' -e '}' vhosts-ssl.conf <VirtualHost *:443> vhost 1 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 <VirtualHost *:443> vhost 2 foobar 2 barfoo 1 foobar 1 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 <VirtualHost *:443> vhost 3 foobar 1 barfoo 1 foobar 2 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 <VirtualHost *:443> vhost 4 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> inserted line 1 inserted line 2

正如我想了解我的错误,并从他们lern,我宁愿有一些解释的答案,甚至可能连接到rtfm,谢谢。

新增2016-10-16

伪代码:

if BLOCK begins with /^<VirtualHost/ and ends with /^</VirtualHost/ and is the ${n-th} BLOCK in FILE_1 then insert content of FILE_2 before last line of ${n-th} BLOCK without touching rest of FILE_1 endif save modified FILE_1

$ {n-th}通过以下方式收集:

$ httpd -t -D DUMP_VHOSTS | grep -i "${SUBDOMAIN}.${DOMAIN}" | awk '/^[^ ]*:443[ ]*/ {print $3}' | sed -e 's|((.*))|1|' | cut -d: -f2

输出是我想通过FILE_2扩展的BLOCK的编号

并且请只有非GNU版本,因为我在FreeBSD上,谢谢。

awk系统不需要连字符

用awk或sedreplace和增加字母和数字

Awk / Unix组合

从文件shell脚本linux grep命令获取信息

在linux中将日志输出更改为configuration文件

awk来拯救!

需要多char记录分隔符,由gawk支持

$ awk 'NR==FNR{insert=$0; next} {print $0 (FNR==2?insert:"") RT}' RS='^$' insert.file RS="</VirtualHost>" file

读取完成的第一个文件并分配给变量插入,同时在第二个记录结束时迭代第二个文件,在记录内容之后打印变量。

纯awk另一个版本

$ awk 'NR==FNR{insert=insert?insert ORS $0:$0; next} /</VirtualHost>/ && ++c==2{print insert} 1' insert.file file

在GNU sed (和BusyBox sed )中, a , b , c , i , r , t , w和:命令之后的文件/ label / text可以用分号分隔,而在其他版本的sed ,文件/标签/文本只能由换行符分隔。

这种行为意味着,而不是定义标签a ,第一个字符串定义的标签

a;n;/^</VirtualHost/!ba;r inserted.txt ,和-e括号分别使用-e一样,脚本必须在标签和分支之后分开。

(也!不能逃脱)

sed -e '/^<VirtualHost/{:a' -e 'n;/^</VirtualHost/!ba' -e 'r inserted.txt' -e '}' vhosts-ssl.conf

或者,脚本可以跨越多行:

sed '/^<VirtualHost/ { :a n /^</VirtualHost/!ba r inserted.txt }' vhosts-ssl.conf

请注意,这种拆分可能不适用于换行符必须转义的情况。 例如,使用a , c和i命令时。

鉴于:

$ cat f1.txt line 1 line 2 line 3 INSERT HERE line 4 line 5 $ cat f2.txt INSERTED LINE 1 INSERTED LINE 2

你可以做:

$ awk 'BEGIN{fc=""} FNR==NR{fc=fc $0 "n";next} /^INSERT HERE/{printf "%s",fc; next} 1' f2.txt f1.txt line 1 line 2 line 3 INSERTED LINE 1 INSERTED LINE 2 line 4 line 5

今天关于Perl、Python、AWK 和 sed 有什么区别?sed grep awk区别的分享就到这里,希望大家有所收获,若想了解更多关于9.6 awk(上) 9.7 awk(下)、AWK / sed-在小于特定值的数字之前在文本文件中写入文本、awk / sed-在比赛后打印第n个值、awk / sed:在特定块号的最后一行之前插入文件内容等相关知识,可以在本站进行查询。

本文标签: