sed的文字处理


12

当前,我有多个文本文件,其内容如下所示(多行):

565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

我希望将每一行更改为以下格式:

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

有什么办法可以使用sed进行上述操作?还是我需要求助于Python?

Answers:


22

您可以使用sed来做到这一点,是的,但是其他工具更简单。例如:

$ awk '{
        printf "%s ", $2; 
        for(i=3;i<=NF;i++){
            printf "%s:%s:1 ",$1,$(i) 
        }
        print ""
       }' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

说明

AWK将分裂上的空白(默认)输入的每一行,从而节省每个字段$1$2$N。所以:

  • printf "%s ", $2; 将打印第二个字段和尾随空格。
  • for(i=3;i<=NF;i++){ printf "%s:%s:1 ",$1,$(i) }:将在字段3上迭代到最后一个字段(NF是字段数),并且对于每个字段,它将打印第一个字段a :,然后是当前字段和a :1
  • print "" :这只是打印最后的换行符。

或Perl:

$ perl -ane 'print "$F[1] "; print "$F[0]:$_:1 " for @F[2..$#F]; print "\n"' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

说明

-a品牌perl表现得像awk和空格分割它的输入。在这里,这些字段存储在array中@F,这意味着第一个字段将是$F[0],第二个字段$F[1]等等。因此:

  • print "$F[1] " :打印第二个字段。
  • print "$F[0]:$_:1 " for @F[2..$#F];:将字段3遍历到最后一个字段($#F是数组中元素的数量@F,因此@F[2..$#F]需要从第3个元素开始直到数组结尾的数组切片)并打印第一个字段a :,然后是当前字段和a :1
  • print "\n" :这只是打印最后的换行符。

12

这里有一个 可怕 sed 办法!

$ sed -r 's/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/; :a s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /; t a; s/ $//' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

更具可读性:

sed -r '
s/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/
:a 
s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /
t a
s/ $//'

笔记

  • -r 使用ERE
  • s/old/new/替换oldnew
  • ^([0-9]+) 在行首保存一些数字
  • \1 向后引用第一个保存的模式
  • :a 标记脚本的这一部分 a
  • ( |$) 空格或行尾
  • t 测试最后一次替换是否成功-如果成功,则执行下一个命令
  • a找到标签,:a然后再做一次
  • s/ $// 删除尾随空格

因此,在将结构添加到第一部分之后,我们反复查找结构的最后一个实例并将其应用于下一个数字...

但是我同意使用其他工具可以使工作更加轻松...


我在等待您的sed解决方案:D
Ravexina

:D我花了一段时间@Ravexina-我认为木匠可以制造一个更清洁的家具
Zanna

5

使用awk:

awk '{printf "%s ",$2; for (i=3; i<=NF; i++) printf $1":"$i":1 "; printf "\n"}' file

或使用bash:

while read -r -a a; do                  # read line to array a
  printf "%s " ${a[1]}                  # print column #1
  for ((i=2;i<${#a[@]};i++)); do        # loop from column #2 to number of columns
    printf "%s " "${a[0]}:${a[$i]}:1"   # print content/values
  done
  echo                                  # print line break
done < file                             # read file from stdin

输出:

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

5

好吧,您可以在sed中完成此操作,但是python也可以。

$ ./reformatfile.py  input.txt                                                                        
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

的内容reformatfile.py如下:

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as fd:
    for line in fd:
        words = line.strip().split()
        pref = words[0]
        print(words[1],end=" ")
        new_words = [ ":".join([pref,i,"1"]) for i in words[2:] ]
        print(" ".join(new_words))

这是如何运作的?确实没有什么特别的事情发生。我们打开第一个命令行参数作为要读取的文件,然后将每一行分解为“单词”或单个项目。第一个单词变为pref变量,然后在第二个(word [1])项目上以空格结尾的标准输出。接下来,我们通过列表理解和.join()函数在pref,每个单词和string的临时列表上构造新的“单词”集"1"。最后一步是将这些打印出来


4

awk

awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i);\
          printf("%s:%s:1\n", $1, $NF)}' file.txt

这一切都是关于将空格分隔的字段格式化为所需的格式:

  • printf("%s ", $2) 打印第二个字段,并在结尾加上空格

  • for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i) 迭代第3至最后一个字段,并以所需格式打印这些字段(第一个字段,然后是冒号,然后是当前字段,然后是冒号,最后是1),并带有尾随空格

  • printf("%s:%s:1\n", $1, $NF) 用换行符打印最后一个字段

例:

% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

% awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i); printf("%s:%s:1\n", $1, $NF)}' file.txt
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.