我有一个很大的(~900MB)制表符分隔的文本文件,我将在下游程序中处理该文件。我需要删除任何缺少值的行。每行都有正确的列数(因此缺失值将对应于 2 个选项卡)。
注意:我的实际数据有大约 200 万行和 80-300 列。可能的字符包括 az AZ 0-9 -(连字符)_(下划线)和制表符(分隔)。文件中没有空格或特殊字符。
我对这种脚本编写很陌生,因此对所提供的任何代码的解释将不胜感激。我通常使用 R,但我的文件大小已经超出了 R 的数据操作功能。
如何在终端(或在 shell 脚本中)删除文件中缺少值的行(例如使用sed
)?
输入文件示例:
Col1 Col2 Col3
A B C
D F
G H I
J K
输出文件示例:
Col1 Col2 Col3
A B C
G H I
答案1
和awk
:
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' file
其实它是就这么简单。
awk
\t
在用标志指定的字段分隔符选项卡处分割输入-F
。当您的内容字段中没有空格时,也可以省略此选项。$1!=""&&...
是一个条件。当此条件成立时,awk
只需打印该行。您也可以写'$1!=""&&$2!=""&&$3!=""{print}'
,但这不是必需的。当未给出任何操作时,awks 默认行为是打印该行。在这里,当 fields$1
、$2
和$3
all 不为空时,即前 3 个字段具有值时,该条件为真。
要写入另一个文件,请使用以下命令:
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' input_file >output_file
编辑:对于未定义的列数,您可以使用此命令awk
,它会检查行中的每个字段:
awk -F"\t" '{for(i=1;i<=NF;i++){if($i==""){next}}}1' file
答案2
...要使以下任何一项发挥作用,您必须首先执行...
t=$(printf \\t) ### because it's hard to demo CTRL+V TAB
...现在,使用 POSIX grep
...
grep -Ev "^$t+|$t($t|$)" <in >out
grep
将选择与模式不匹配的行 - 它使用|
或者元字符来表示^
行头选项卡,或两个连续的选项卡,或$
行尾选项卡 - 据我所知,这是唯一可能的失败情况。
如果没有-v
否定开关,它可能是:
grep -E "([^$t]+$t){2}[^$t]" <in >out
...指定字符类中一个或多个字符的模式组的{
出现计数,这些字符不是制表符后跟一个制表符。}
(
)
+
[
]
^
...或者使用 POSIX sed
...
sed -ne"s/[^$t][^$t]*/&/3p" <in >out
...或者...
sed -ne"s/[^$t]\{1,\}/&/3p" <in >out
...或者使用 GNU 或 BSDsed
系统...
sed -Ene"s/[^$t]+/&/3p" <in >out
...where ot 默认情况下sed
不-n
打印任何行,除非它可以s///
代替&
至少一个[^
非制表]
符的最长可能序列的行上的第三次出现。
(为了可移植性,应该首选使用文字制表符。这个答案的原始版本使用\
反斜杠转义符,它是不是有帮助。在字符类中使用\
反斜杠转义肯定会限制代码的适用性。)[
]
答案3
如果您的字段不能包含空格,则空字段意味着制表符作为第一个字符 ( ^\t
)、制表符作为最后一个字符 ( \t$
) 或两个连续的制表符 ( \t\t
)。因此,您可以过滤掉包含以下任何内容的行:
grep -Ev $'^\t|\t\t|\t$' file
如果可以有空格,事情就会变得更加复杂。如果您的字段可以以空格开头,请使用它(它认为只有空格的字段为空):
grep -Pv '\t\s*(\t|$)|\t$|^\t' file
该更改会过滤掉与制表符匹配的行,后跟 0 个或多个空格,然后是另一个制表符或行尾。
如果最后一个字段只包含空格,这也会失败。为了避免这种情况,请使用perl
和-F
选项-a
将输入拆分到@F
数组中,告诉它打印,除非其中一个字段为空 ( /^$/
):
perl -F'\t' -lane 'print unless grep{/^$/} @F' file
答案4
你可以尝试这样的事情:
grep "^[a-zA-Z0-9]\+[[:space:]][a-zA-Z0-9]\+[[:space:]][a-zA-Z0-9]\+$" input_file > output_file
的目的grep
是(或不)在一个或多个文件中查找与给定模式匹配的字符串。此处,该模式[a-zA-Z0-9]\+
匹配一个或多个字母数字字符,后跟空格或制表符。行的开头与 匹配^
,而$
表示行的结尾。如果列中使用了其他字符,则应将它们添加到上面的字符类中。最后,>
将匹配的输出重定向到输出文件。
另请查看下面 @terdon 的评论,了解潜在的陷阱和替代解决方案。请注意,如果您在 Linux/Unix 环境中工作,那么它的用处grep
远远超出了这个特定的解决方案。