【问题标题】:transforming the text data in unix or Linux with text editor like sed or awk or tr使用 sed 或 awk 或 tr 等文本编辑器在 unix 或 Linux 中转换文本数据
【发布时间】:2018-10-18 18:20:57
【问题描述】:

我有包含数千个操作系统数据的文件,例如括号内的 IP 地址以及逗号和连字符。我要删除所有这些替换 IP 地址以出现在没有空白行或空格的换行符中..

下面是一个示例文件..

$ cat file1
mynetgroup-test (192.19.23.57,-,) (192.19.23.58,-,)

我现在的解决方案如下,但它可能会更好或以更好的控制方式进行简化

$ cat file1 | sed -e 's/[(,) ]/\n/g' | tr -d "-" | sed '/^$/d'
mynetgrouptest
192.19.23.57
192.19.23.58

【问题讨论】:

  • where should be removing all of them 你的意思是你只需要地址,对吧?请确认一次。
  • @RavinderSingh13 Parenthesis along with comma and hyphen 这也需要mynetgroup-test

标签: awk sed tr


【解决方案1】:

使用 GNU awk 进行多字符 RS:

$ awk -v RS='\\s+' '{gsub(/[-,)(]/,"")}1' file
mynetgrouptest
192.19.23.57
192.19.23.58

【讨论】:

    【解决方案2】:

    只使用grep 怎么样?

    $ egrep -o '[a-z][a-z-]+|[0-9]+(\.[0-9]+){3}' input.txt
    mynetgroup-test
    192.19.23.57
    192.19.23.58
    

    如果您的操作系统不喜欢使用egrep,当然是grep -E

    此解决方案仅匹配看起来像主机名和 IP 地址的模式,并且(感谢 grep 的 -o 选项)仅按看到的顺序打印匹配的部分。

    另一种表示法可能是使用grep-e 选项来包含多个正则表达式:

    egrep -o -e '[a-z][a-z-]+' -e '[0-9]+(\.[0-9]+){3}' input.txt
    

    当然,如果您真的想使用其他工具,以下可能会起作用:

    $ awk '{print $1; for(i=2;i<=NF;i++) { gsub(/[^0-9.]/,"",$i); print $i } }' input.txt
    mynetgroup-test
    192.19.23.57
    192.19.23.58
    

    这会打印第一个字段,然后逐步删除剩余字段,去除不需要的字符,然后打印字段。

    另一种 awk 选择可能是这样的:

    $ awk '{for(i=2;i<=NF;i++) { gsub(/[^0-9.]/,"",$i) } } 1' OFS="\n" input.txt
    

    这会执行相同的单步执行字段,然后使用脚本末尾的1 速记打印整个记录。 OFS 变量赋值与-v 选项略有不同,但在这种情况下工作方式相同。

    如果你不介意管道,你可以用 sed 做这样的事情:

    tr ' ' '\n' < input.txt | sed -ne '/^[a-z]/{p;b' -e '}' -e 's/[^0-9.]//gp'
    

    这会将单词分隔到单独的行中,以便 sed 更轻松地处理(以及模拟最终的输出格式)。然后 sed 脚本 (1) 打印任何以字母开头的行,假设它是一个主机名,然后 branches 将我们带到下一行,并且 (2) 从任何其他行中删除任何非 IP 地址字符,并打印出来。

    这里的 sed 符号是用 bsd sed 测试过的,但在 GNU sed 上也应该可以正常工作。

    【讨论】:

      【解决方案3】:

      如果您只需要地址,那么以下内容可能对您有所帮助。

      awk '{while(match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)){print substr($0,RSTART,RLENGTH);$0=substr($0,RSTART+RLENGTH+1)}}'  Input_file
      

      EDIT1:如果您的 Input_file 与所示示例 100% 相同,那么以下内容也可能对您有所帮助。

      awk -v RS=" " '{gsub(/\(|,|-|\)/,"");gsub(/$\n$/,"")} 1'   Input_file
      

      EDIT2:也从 Ghoti sir 的解决方案中获得了一些正则表达式的灵感。

      awk -v RS=" " '!/[a-zA-Z]+/{gsub(/[^0-9.]+/,"");gsub(/$\n$/,"")} 1'   Input_file
      

      【讨论】:

      • @krock1516,现在请检查我的EDIT1,它也会根据您的问题打印所有行,让我知道它是怎么回事?
      • @krock1516,很高兴它对你有所帮助,过了一段时间你可以选择任何一个你认为好的答案作为正确答案,加油,继续学习和分享知识。
      • 感谢您的信任。 ;) 请注意,最后一个(编辑 2)解决方案不能很好地处理多条记录,因为每行的最后一条记录由下一个字段使用换行符而不是空格分隔。如果你使用 gawk 或 mawk,你可以指定 RS='[[:space:]]' 来解决这个问题,但这不适用于 BSD awk(也用于 macOS)。
      【解决方案4】:

      sed

      $ sed -E 's/\((([0-9]+\.){3}[0-9]+),-,\)/\n\1/g' file
      
      mynetgroup-test 
      192.19.23.57 
      192.19.23.58
      

      您可以微调 IP 地址匹配,但这种启发式方法应该没问题。

      【讨论】:

      • 那将是 GNU sed,因为\n,我猜。如果你把它做成便携的,这个看起来就不那么漂亮了。 :-)
      • thx,他的脚本也使用\n,所以应该适用于这种情况。也许不是犹太洁食,但我不担心丢弃脚本的可移植性......
      • 啊,我尽量牢记所有答案的可移植性。你永远不知道下一个搜索此主题行的访问者将使用什么操作系统。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-10
      • 2020-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      相关资源
      最近更新 更多