如何在使用sed时排除特定模式

时间:2017-04-21 06:49:09

标签: unix sed sh

我有一个空格分隔的文件,我需要将其转换为管道分隔但是当它遇到每行中的特定模式时,它需要在执行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

对此方面的任何帮助表示赞赏。

4 个答案:

答案 0 :(得分:3)

在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记录末尾的管道。

答案 1 :(得分:1)

它不是特别漂亮,但两个表达式 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)|

但是我把最后的管道作为我的输入文件中没有空格的尾随空格。无论哪种方式,它都是皮肤这种猫的另一种方式。

答案 2 :(得分:1)

如果我理解正确的话,这些是要求:

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

以下将适用于给定的样本

$ 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/ +|$/|/,如果不包含),则将第一次出现的一个或多个空格或行尾更改为|

答案 3 :(得分:0)

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前面。