Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash awk筛选具有有效电子邮件地址的行_Bash_Awk - Fatal编程技术网

Bash awk筛选具有有效电子邮件地址的行

Bash awk筛选具有有效电子邮件地址的行,bash,awk,Bash,Awk,我对bash和awk还不熟悉,我花了好几天的时间试图学习它。我认为我非常接近解决方案,但还没有完全解决。所以,请求你的帮助。请注意,我不希望使用grep,因为我发现它要慢得多 我有大量的文本文件,每个都有几百MB的大小。不幸的是,它们在任何一种格式中都没有完全标准化。加上这里有很多遗产,还有很多垃圾和乱七八糟的文字。我希望检查所有这些文件以查找具有有效电子邮件ID的行,如果存在,则将其打印到文件中。请注意,我正在windows10上使用Cygwin(不确定这是否重要) 文本文件: !bar@fo

我对bash和awk还不熟悉,我花了好几天的时间试图学习它。我认为我非常接近解决方案,但还没有完全解决。所以,请求你的帮助。请注意,我不希望使用grep,因为我发现它要慢得多

我有大量的文本文件,每个都有几百MB的大小。不幸的是,它们在任何一种格式中都没有完全标准化。加上这里有很多遗产,还有很多垃圾和乱七八糟的文字。我希望检查所有这些文件以查找具有有效电子邮件ID的行,如果存在,则将其打印到文件中。请注意,我正在windows10上使用Cygwin(不确定这是否重要)

文本文件:

!bar@foo.com,address
#john@foo.com;address
john@foo.com;address µÖ
email1@foo.com;username;address
email2@foo.com;username
  email3@foo.com,username;address   [spaces at the start of the row]
 email4@foo.com|username|address   [tabs at the start of the row]
awk -F'[,|;: \t]+' '{
    gsub(/^[ \t]+|[ \t]+$/, "")
    if (NF>1 && tolower($1) ~ /[0-9a-z_\-\.\+]+@[0-9a-z_\-\.]+\.[a-z0-9]+/)
    {
        r=gensub("[,|;: \t]+",":",1,$0)
        print r > "file_good"
    }
    else
        print $0 > "file_ignore"
}' *.txt
代码:

!bar@foo.com,address
#john@foo.com;address
john@foo.com;address µÖ
email1@foo.com;username;address
email2@foo.com;username
  email3@foo.com,username;address   [spaces at the start of the row]
 email4@foo.com|username|address   [tabs at the start of the row]
awk -F'[,|;: \t]+' '{
    gsub(/^[ \t]+|[ \t]+$/, "")
    if (NF>1 && tolower($1) ~ /[0-9a-z_\-\.\+]+@[0-9a-z_\-\.]+\.[a-z0-9]+/)
    {
        r=gensub("[,|;: \t]+",":",1,$0)
        print r > "file_good"
    }
    else
        print $0 > "file_ignore"
}' *.txt
预期输出到:文件\u良好

email1@foo.com:username;address
email2@foo.com:username
email3@foo.com:username;address
email4@foo.com:username|address
代码问题:

!bar@foo.com,address
#john@foo.com;address
john@foo.com;address µÖ
email1@foo.com;username;address
email2@foo.com;username
  email3@foo.com,username;address   [spaces at the start of the row]
 email4@foo.com|username|address   [tabs at the start of the row]
awk -F'[,|;: \t]+' '{
    gsub(/^[ \t]+|[ \t]+$/, "")
    if (NF>1 && tolower($1) ~ /[0-9a-z_\-\.\+]+@[0-9a-z_\-\.]+\.[a-z0-9]+/)
    {
        r=gensub("[,|;: \t]+",":",1,$0)
        print r > "file_good"
    }
    else
        print $0 > "file_ignore"
}' *.txt
  • 我找不到过滤非ascii字符(不可打印字符)的方法
  • 由于某些原因,代码允许没有有效电子邮件地址的行。例如:!bar@foo.com ; #john@foo.com ; 等

  • 任何帮助都将不胜感激

    这不是一个完整的解决方案,但我可以想到一些初步步骤,这些步骤可能会使流程的其余部分变得更加简单

    cat textfile | tr ';' '\n' | tr ',' '\n' | tr '\|' '\n' > textfile2
    mv textfile2 textfile
    sed -n '/\@/p' textfile > emails
    sed -i '/\@/d' textfile
    
    这将要做的是,尝试将所有这些分隔符转换成新行,这将产生将分隔字段放在单独行上的效果。在此之后,对包含“@”符号的所有行进行暴力搜索,希望至少能得到几个电子邮件地址,然后可以将这些地址转储到单独的文件中,并从原始文件中删除。从那里,如果你能找到一个共同的锚,你可能可以构建一个类似的启发式方法来提取用户名和snail地址


    根据我的经验,正则表达式可以诱发字面意义上的偏头痛。在可能的情况下,我会尽量使用最简单的解决方案。如前所述,这很可能不是完美的;但这只是一个开始。

    虽然与所述目标相关的还有其他复杂性,但您最初的awk程序没有按预期工作的主要原因是正则表达式缺少锚定:

    tolower($1) ~ /^[0-9a-z_\-\.\+]+@[0-9a-z_\-\.]+\.[a-z0-9]+$/
    

    $1~/…/
    更改为
    $1~/^…$/
    。另外,原始程序的
    r=gensub
    部分似乎没有做任何有用的事情(我在其他地方没有看到
    r
    gensub
    特定于GNU
    awk
    ——在这种情况下,可能需要的只是
    sub

    此注释可能会有所帮助:您的问题是,根据发布的示例输入显示预期的输出(因此,我们可以看到,例如,如果您希望打印一行或仅打印一行中的电子邮件地址。还可以在示例输入/输出中添加至少一种情况,即您在一行中有多个电子邮件地址,以及您的文本可能被误解为电子邮件地址但实际上无效。
    #john@foo.com
    不是一封有效的电子邮件地址,但
    john@foo.com
    就是这样,请在您的问题中解释工具应该如何知道
    #john@foo.com
    是有效的电子邮件地址
    john@foo.com
    之前正好有一个
    而不是一个无效的电子邮件地址。您好,Ed。我使用的正则表达式应该能够过滤掉“#”或任何其他规范不知道错误在哪里:
    tolower($1)~/[0-9a-z\-\.\+]+@[0-9a-z\.-\.]+\.[a-z0-9]+/
    它锚定为@user…除此之外,regexp还有一些问题。1)转义
    -
    不可移植,只需将其放在括号表达式的开头或结尾。2)
    +
    不是括号表达式中的元字符,因此它们不应转义。3) 使用小写字母的字符范围是不可移植的,您应该使用字符类。因此,你不应该把它写成
    /^[0-9a-z\-\\\\\.+][0-9a-z\\-\.+\.+\.[[a-z0-9]+$/
    ,你应该把它写成
    /^[:alnum:][:alnum:][-]+\.[:alnum:][-]+$/
    ,并且把
    改为
    tolower($1
    ,因为RE现在可以处理所有的情况。感谢用户13586221。。。我已经更正了上面的代码,以展示变量“r”的使用。我应该用gsub替换gensub吗?如果是,正确的代码是什么?@rogerwhite是的,可以与GNU awk一起使用。如果您不需要同时使用
    r
    和原始
    $0
    r=gensub(“[,|::\t]+”,“:”,1)
    可以替换为
    sub(“[,|:;:\t]+”,“:”
    )。主要区别在于
    sub
    gsub
    修改原始字符串并返回所做替换的数量,而
    gensub
    返回修改后的字符串
    gensub
    还具有其他功能,如backreferences&全局替换的第三个参数或第n个匹配。