删除具有给定模式的特殊字符的行

时间:2013-12-17 11:50:41

标签: linux shell unix sed awk

我正在尝试使用不带\前缀的特殊字符。以下是特殊字符:

^$%.*+?!(){}[]|\

我需要在第二列中检查所有上面没有\前缀的特殊字符。我正在尝试使用awk完成此操作,但没有运气。我想要输出如下。

input.txt中

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y
8,wor\+k

output.txt的

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y

第7行和第5行在output.txt中,因为有2个特殊的字符(一个是反斜杠,另一个没有反斜杠)

3 个答案:

答案 0 :(得分:2)

“最终”最终编辑:我想允许“\ x”无论x是什么,但OP似乎不想要那样,所以我也修复了它。

试图找到一个“聪明”的正则表达式(在“\\”或任何损害数量为“\”的情况下窒息,但显然对其余部分有效...)

我用awk重写它以“状态自动机”的方式来做:

这个想法:

如果处于“正常模式”,我们会遇到除“\”之外的特殊字符? :我们打印线!  如果处于“正常模式”,我们会遇到“\”? :我们进入“转义模式”,在该模式下,忽略下一个字符       (但如果我们没有下一个字符,我们也需要打印该行!)

脚本:

awk -F"," '
  {
    IN_ESCAPED_MODE=0 ;
    for (i=1 ; i<=length($2) ; i++)
     {  char=substr($2,i,1)

        if ( IN_ESCAPED_MODE == 0)
     {  if ( index(".^$%*+?!(){}[]|",char) > 0 )
             {  print $0 ; break ;
             }

            if ( index("\\" , char ) > 0 )
             {  IN_ESCAPED_MODE=1 ; continue ;
             }
         }

        if ( IN_ESCAPED_MODE == 1)
     {   if ( index(".^$%*+?!(){}[]|\\",char) > 0 )
           {  IN_ESCAPED_MODE=0 ; continue ;
               }
             else
               {  IN_ESCAPED_MODE=0 ; print $0; break;
               }
         }
     }

    if (IN_ESCAPED_MODE == 1)
     {
        print $0 ; break ;
     }

  }
'  input.txt > output.txt

通过这个改变,你将获得与OP相同的输出,当它包含“\ e”时会输出一行......我觉得很奇怪:对我来说“\ e”很好,我们可以“逃避“什么?

有了这个输入:

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y
8,wor\+k

10,\
11,\\
12,\\\
13,.
14,\.
15,..
16,^
17,\^
18,$
19,\$
20,%
21,\%
22,*
23,\*
24,+
25,\+
26,?
27,\?
28,!
29,\!
30,(
31,\(
32,)
33,\)
34,{
35,\{
36,}
37,\}
38,[
39,\[
40,]
41,\]
42,|
43,\|

输出:

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y
10,\
12,\\\
13,.
15,..
16,^
18,$
20,%
22,*
24,+
26,?
28,!
30,(
32,)
34,{
36,}
38,[
40,]
42,|

(这次看起来真的很有用!)

如果您希望允许任何“\ x”而不仅仅是“x”是特殊字符:

改变“中间线”:

        if ( IN_ESCAPED_MODE == 1)
         {  if ( index(".^$%*+?!(){}[]|\\",char) > 0 )
             {  IN_ESCAPED_MODE=0 ; continue ;
             }
            else
             {  IN_ESCAPED_MODE=0 ; print $0; break;
             }
         }

成:

        if ( IN_ESCAPED_MODE == 1)
         {  IN_ESCAPED_MODE=0 ; continue ;
         }

由于历史原因:regexp(在“大多数”情况下工作但在某些情况下被阻塞,例如,如果有“\\”):

 egrep '[^\][].^$%*+?!(){}[|]|[^\][\][^].^$%*+?!(){}[|\]'   input.txt > output.txt

但那个人不会显示第12行,例如......

好读:http://www.regular-expressions.info/charclass.html ....和http://www.gnu.org/software/gawk/manual/html_node/Gory-Details.html(吓人......)

答案 1 :(得分:1)

您可以尝试以下操作:

awk '
{
    line=$0
    sub(/\\[\^$%.*+?!(){}\[\]|\\]/,"")
    if(/[\^$%.*+?!(){}\[\]|\\]/)
        print line
}' input.txt

答案 2 :(得分:1)

sed '/[]\\^$%.*+?!(){}[|]/ {
  h
  s/\\[]\\^$%.*+?!(){}[|]/_/g
  /[]\\^$%.*+?!(){}[|]/ {
    x
    p
    }
  }' YourFile

可以不同地解释shell和sed(特别是\)。适用于我的AIX / KSH