使用 sed 或 awk 格式化文本

问题描述 投票:0回答:8

我正在尝试格式化以下实际输出以使每个磁盘位于同一行

0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>
   /pci@4,0/pci8086,347c@4/e,487c@0/disk@1
   /dev/chassis/SYS/DBP/HDD0/NVME/disk
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>
   /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1
   /dev/chassis/DBP/HDD1/NVME/disk
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>
   /pci@0,0/pci8e,4872@17/disk@0,0
   /dev/chassis/MB/SSDR0/SSD0/disk
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>
   /pci@0,0/pci08e,4872@17/disk@2,0
   /dev/chassis/SYS/MB/SSDR0/SSD1/disk

尝试获得如下所示的预期输出,

0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347c@4/e,487c@0/disk@1| /dev/chassis/SYS/DBP/HDD0/NVME/disk|
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1| /dev/chassis/DBP/HDD1/NVME/disk|
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>| /pci@0,0/pci108e,4872@17/disk@0,0| /dev/chassis/MB/SSDR0/SSD0/disk|
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>| /pci@0,0/pci108e,4872@17/disk@2,0| /dev/chassis/SYS/MB/SSDR0/SSD1/disk|

我在下面尝试过,

cat actual_output | tr -s " " | tr "\n" "|"

结果都是单行,

0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347c@4/e,487c@0/disk@1| /dev/chassis/SYS/DBP/HDD0/NVME/disk|1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1| /dev/chassis/DBP/HDD1/NVME/disk|2. c3t0d0 <ATA-Micron_5300_MAAAD-D3MU-223.57GB>| /pci@0,0/pci108e,4872@17/disk@0,0| /dev/chassis/MB/SSDR0/SSD0/disk|3. c4t2d0 <ATA-Micron_5300_MTFD-D3MU-223.57GB>| /pci@0,0/pci108e,4872@17/disk@2,0| /dev/chassis/SYS/MB/SSDR0/SSD1/disk|

现在需要用换行符替换 0. until next 1. contents( ), 这样就会得到预期的结果。 我们有任何正则表达式来做同样的事情吗?

TIA

linux awk sed tr
8个回答
2
投票

paste
如果每组总是 3 行,则串行模式可以工作:

paste -sd'||\n'

输出:

0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>|   /pci@4,0/pci8086,347c@4/e,487c@0/disk@1|   /dev/chassis/SYS/DBP/HDD0/NVME/disk
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>|   /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1|   /dev/chassis/DBP/HDD1/NVME/disk
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>|   /pci@0,0/pci8e,4872@17/disk@0,0|   /dev/chassis/MB/SSDR0/SSD0/disk
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>|   /pci@0,0/pci08e,4872@17/disk@2,0|   /dev/chassis/SYS/MB/SSDR0/SSD1/disk

2
投票

使用 GNU

awk

$ awk '/^\s/{r=r "| " $0;next} NR!=1{print r "|"} {r=$0} END{print r "|"}' data.txt
0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>|    /pci@4,0/pci8086,347c@4/e,487c@0/disk@1|    /dev/chassis/SYS/DBP/HDD0/NVME/disk|
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>|    /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1|    /dev/chassis/DBP/HDD1/NVME/disk|
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>|    /pci@0,0/pci8e,4872@17/disk@0,0|    /dev/chassis/MB/SSDR0/SSD0/disk|
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>|    /pci@0,0/pci08e,4872@17/disk@2,0|    /dev/chassis/SYS/MB/SSDR0/SSD1/disk|

使用 GNU

sed

sed -zE 's/\n\s+/| /g;s/(\n|$)/|&/g' data.txt
0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347c@4/e,487c@0/disk@1| /dev/chassis/SYS/DBP/HDD0/NVME/disk|
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1| /dev/chassis/DBP/HDD1/NVME/disk|
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>| /pci@0,0/pci8e,4872@17/disk@0,0| /dev/chassis/MB/SSDR0/SSD0/disk|
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>| /pci@0,0/pci08e,4872@17/disk@2,0| /dev/chassis/SYS/MB/SSDR0/SSD1/disk|

-z
将整个输入处理为一行,
-E
用于扩展正则表达式。
s/\n\s+/| /g
| 
替换换行符后跟一个或多个空格。
s/(\n|$)/|&/g
在所有剩余的换行符或文件末尾之前插入
|


2
投票

使用 GNU

awk
请尝试以下
awk
代码。仅在所示示例中编写和测试。

awk -v RS='(^|\n)[0-9]+\\.' -v OFS="| " '
rt{
  sub(/^\n/,"",RT)
  $1=$1
  print rt " " $0,_
}
{ rt=RT }
'  Input_file

2
投票

使用任何 awk 并且不依赖于每个输入记录有 3 行:

$ awk '/^[0-9]/{ if (NR>1) print rec; rec=$0; next} {sub(/ */,"| "); rec=rec $0} END{print rec}' file
0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347c@4/e,487c@0/disk@1| /dev/chassis/SYS/DBP/HDD0/NVME/disk
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1| /dev/chassis/DBP/HDD1/NVME/disk
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>| /pci@0,0/pci8e,4872@17/disk@0,0| /dev/chassis/MB/SSDR0/SSD0/disk
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>| /pci@0,0/pci08e,4872@17/disk@2,0| /dev/chassis/SYS/MB/SSDR0/SSD1/disk

如果你真的想要一个

|
添加到每个输出行的末尾,那么只需将每个
print rec
更改为
print rec"|"
.


1
投票

使用 GNU

sed

$ sed -Ez ':a;s/([0-9]+\.[^\n]*)\n +/\1| /;ta;s/\n|$/|&/g' input_file
0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347c@4/e,487c@0/disk@1| /dev/chassis/SYS/DBP/HDD0/NVME/disk|
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1| /dev/chassis/DBP/HDD1/NVME/disk|
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>| /pci@0,0/pci8e,4872@17/disk@0,0| /dev/chassis/MB/SSDR0/SSD0/disk|
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>| /pci@0,0/pci08e,4872@17/disk@2,0| /dev/chassis/SYS/MB/SSDR0/SSD1/disk|

1
投票

修改一个数据集只有两行:

$ cat disk.dat
0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>
   /pci@4,0/pci8086,347c@4/e,487c@0/disk@1
   /dev/chassis/SYS/DBP/HDD0/NVME/disk
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>
   /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1
   /dev/chassis/DBP/HDD1/NVME/disk
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>
   /pci@0,0/pci8e,4872@17/disk@0,0
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>
   /pci@0,0/pci08e,4872@17/disk@2,0
   /dev/chassis/SYS/MB/SSDR0/SSD1/disk

扩展OP的当前代码:

cat disk.dat | tr -s " " | tr "\n" "|" | sed -E "s/\|([0-9])/\|\n\1/g; s/$/\n/"

地点:

  • sed
    脚本的前半部分在管道(
    \n
    )和数字(
    |
    )之间放置一个
    [0-9]
  • sed
    脚本的第二部分在行尾添加一个
    \n

另一种

awk
想法:

awk -F'.' '                                        # input field delimiter is a period
           { sub(/[[:space:]]+/,"",$1) }           # remove leading white space from 1st field
($1+0)==$1 { if (NR>1) print ""; pfx="" }          # if 1st field is numeric; if beyond 1st row then terminate previous line of output; reset prefix to empty string
           { printf "%s%s|", pfx, $0; pfx=" " }    # print prefix plus current line; reset prefix to a single space
END        { if (NR>=1) print "" }                 # if we had at least one row of input then terminate previous line of output
' disk.dat

这两个都会产生:

0. ct1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347c@4/e,487c@0/disk@1| /dev/chassis/SYS/DBP/HDD0/NVME/disk|
1. c2t1d0 <INTEL-ADDPF2KX076T9S-2CV1-6.19TB>| /pci@4,0/pci8086,347d@5/apci108e,487c@0/disk@1| /dev/chassis/DBP/HDD1/NVME/disk|
2. c3t0d0 <ATA-Min_5300_MAAAD-D3MU-223.57GB>| /pci@0,0/pci8e,4872@17/disk@0,0|
3. c4t2d0 <ATA-Min_5300_MTFD-D3MU-223.57GB>| /pci@0,0/pci08e,4872@17/disk@2,0| /dev/chassis/SYS/MB/SSDR0/SSD1/disk|

0
投票

您可以将 awk 与模运算符一起使用。在一个条件下:如果当前行不能被 3 整除则管道符号“|”添加,否则添加新行:

awk 'BEGIN{ ORS=""; }{printf "%s%s", $0,(NR%3?"|":"\n");}' actual_output

0
投票

这可能对你有用(GNU sed):

sed -E '/^\S/{:a;x;1!s/\n(\s)+|$/|\2/gp;d};H;$!d;ba' file

会有两个条件;一行不以空格开头或以空格开头的地方。

如果一行不以空格开头(新记录):

  1. 切换到等待空间
  2. 如果不是第一行,将所有换行符(后跟空格)替换为
    | 
    并打印结果。
  3. 删除结果。

如果行以空格开头(中间记录):

  1. 将当前行附加到保留空间
  2. 如果不是最后一行,则删除该行
  3. 否则,跳回并像处理新记录一样处理。

注意每次遇到新记录时,都会处理并打印先前存储的记录。还有 first 和 last 之间的对称性以及

x
H
的使用的不对称性。


替代方案:

sed -zE 's/\n\s+/| /g;s/.*/&|/gm' file

注意全麦编程的一个很好的例子。第一个替换将所有行减少为单独的记录。第二次替换将

|
附加到每条记录。

© www.soinside.com 2019 - 2024. All rights reserved.