【问题标题】:How to exclude specific pattern while using sed如何在使用 sed 时排除特定模式
【发布时间】:2017-09-18 01:07:40
【问题描述】:

我有一个以空格分隔的文件,我需要将其转换为管道分隔,但是当它在每一行中遇到特定模式时,它需要在执行 sed 时排除这些模式。

a char(30) NOT NULL
b LARGEINT NOT NULL
c TIMESTAMP
d numeric(10, 3)

预期输出

a|char(30)|NOT NULL
b|LARGEINT|NOT NULL
c|TIMESTAMP|
d|numeric(10, 3)|

在替换空格时,需要忽略 (10, 3) 中的空格和 NOT NULL。 我尝试了以下方法,但没有成功

sed -ri '|, |!s|\ /\|/g' abc.txt

感谢您提供这方面的任何帮助。

【问题讨论】:

  • 所以输出应该是这样的:a|char(30)|NOT NULL?
  • 也给出你的预期输出。是否要替换char(30)NOT NULL 之间的空格
  • 预期的输出是 a|char(30)|NOT NULL
  • 这两行后面必须有一个space

标签: unix sed sh


【解决方案1】:

在 GNU awk 中使用 FPAT:

$ awk '
BEGIN {
    FPAT="([^ ]+)|([^ ]*NOT NULL[^ ]*)|([^ ]*numeric([^)]*)[^ ]*)"  # set FPAT
    OFS="|"                                                         # set OFS
}
{ NF=3; $1=$1 }                                                     # rebuild record (1)
1' file                                                             # and output
a|char(30)|NOT NULL
b|LARGEINT|NOT NULL
c|TIMESTAMP|
d|numeric(10, 3)|

(1)NF=3 将字段计数静态设置为 3,并导致 c 和 d 记录末尾的管道。

【讨论】:

  • FPAT++ 的用法很好,但仍然不相信 OP 故意在最后两行添加 |
  • @Inian 不知道,但无论如何我都会修复它。
【解决方案2】:

它不是特别漂亮,但是 两个表达式 sed 表达式可以工作,

$ sed -e 's/\([^,T]\)[ ]/\1\|/g' file.txt | sed -e 's/\([^O]T\)[ ]/\1\|/'
a|char(30)|NOT NULL
b|LARGEINT|NOT NULL
c|TIMESTAMP
d|numeric(10, 3)

如果你真的想要TIMESTAMP) 之后的管道,你可以在末尾添加三分之一,例如

$ sed -e 's/\([^,T]\)[ ]/\1\|/g' file.txt | sed -e 's/\([^O]T\)[ ]/\1\|/' \
-e 's/\([^L]\)$/\1\|/'
a|char(30)|NOT NULL
b|LARGEINT|NOT NULL
c|TIMESTAMP|
d|numeric(10, 3)|

但我将最后的管道作为输入文件中的尾随空格,而我的输入文件中不存在。不管怎样,这都是给这只猫剥皮的另一种方式。

【讨论】:

    【解决方案3】:

    如果我正确理解了这个问题,这些是要求:

    • 将输入文件转换为以|为分隔符的三列输出
    • 第三个字段可能为空
    • 输入以空格分隔,但
      • 第三个字段可能包含空格
      • 输入中的第二个字段可能包含 () 内的文本,其中可能包含空格

    以下将适用于给定的样本

    $ cat ip.txt 
    a char(30) NOT NULL
    b LARGEINT NOT NULL
    c TIMESTAMP
    d numeric(10, 3)
    
    $ sed -E 's/ +/|/; s/\) */)|/; /\)/!s/ +|$/|/' ip.txt 
    a|char(30)|NOT NULL
    b|LARGEINT|NOT NULL
    c|TIMESTAMP|
    d|numeric(10, 3)|
    
    • s/ +/|/ 将第一次出现的一个或多个空格更改为 |
    • s/\) */)|/ 先处理麻烦的第二个字段。将) 和可选空格更改为)|
      • 当然,假设,没有其他字段包含()
    • /\)/!s/ +|$/|/ 对于剩余的行,如果它不包含 ),则将第一次出现的一个或多个空格或行尾更改为 |

    【讨论】:

      【解决方案4】:
      awk '/^[cd]/{$NF=$NF"|"}{sub(/ /,"|")sub(/ N/,"|N")}1' file
      
      a|char(30)|NOT NULL
      b|LARGEINT|NOT NULL
      c|TIMESTAMP|
      d|numeric(10, 3)|
      

      会发生什么? 它首先在以 c 或 d 开头的行的末尾添加管道。

      第一个空白区域中的第一个子替换管道。

      第二个子把管道放在NOT前面。

      【讨论】:

      • 请编辑您的答案以包含一些解释。仅代码的答案对教育未来的 SO 读者几乎没有作用。您的答案因质量低劣而在审核队列中。
      猜你喜欢
      • 2017-01-04
      • 2017-10-13
      • 2014-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多