Gai*_*tus 5 sed shell-script text-processing csv
我有一个很大的(~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
Run Code Online (Sandbox Code Playgroud)
示例输出文件:
Col1 Col2 Col3
A B C
G H I
Run Code Online (Sandbox Code Playgroud)
与awk:
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' file
Run Code Online (Sandbox Code Playgroud)
其实就是这么简单。
awk在\t由-F标志指定的字段分隔符选项卡处拆分输入。当您的内容在字段中没有空格时,这也可以省略。$1!=""&&...是一个条件。当此条件为真时,awk只需打印该行。你也可以写'$1!=""&&$2!=""&&$3!=""{print}',但这不是必需的。awks 的默认行为是在没有给出任何操作时打印该行。这里,条件为真时域$1,$2和$3所有不为空,因此当第3场有一个值。要写入另一个文件,请使用以下命令:
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' input_file >output_file
Run Code Online (Sandbox Code Playgroud)
编辑:对于未定义的列数,您可以使用 this awk,它会检查该行中的每个字段:
awk -F"\t" '{for(i=1;i<=NF;i++){if($i==""){next}}}1' file
Run Code Online (Sandbox Code Playgroud)
...要使以下任何一项工作,您必须首先执行...
t=$(printf \\t) ### because it's hard to demo CTRL+V TAB
Run Code Online (Sandbox Code Playgroud)
...现在,使用 POSIX grep...
grep -Ev "^$t+|$t($t|$)" <in >out
Run Code Online (Sandbox Code Playgroud)
grep将选择与模式不匹配的行 - 使用| 或元字符来表示^行首制表符,或两个连续制表符,或$行尾制表符 - 这是唯一可能的失败情况与 I可以告诉。
如果没有-v否定开关,它可能是:
grep -E "([^$t]+$t){2}[^$t]" <in >out
Run Code Online (Sandbox Code Playgroud)
...指定的{出现计数}的(图案组)的+在所述一个或多个字符[类]的字符的其是^未接片,随后一个选项卡。
...或使用 POSIX sed...
sed -ne"s/[^$t][^$t]*/&/3p" <in >out
Run Code Online (Sandbox Code Playgroud)
...或者...
sed -ne"s/[^$t]\{1,\}/&/3p" <in >out
Run Code Online (Sandbox Code Playgroud)
...或带有 GNU 或 BSD seds ...
sed -Ene"s/[^$t]+/&/3p" <in >out
Run Code Online (Sandbox Code Playgroud)
...默认情况下sed不会-n打印任何行,除非它可以s///代替&自己在至少一个[^非制表]符的最长可能序列的行上的第三次出现。
(使用文字制表符应该是可移植性的首选。这个答案的原始版本使用\反斜杠转义,它没有帮助。\在[字符类中使用反斜杠转义肯定]会限制你的代码的适用性。)
如果您的字段永远不能包含空格,则空字段意味着制表符作为第一个字符 ( ^\t)、制表符作为最后一个字符 ( \t$) 或两个连续的制表符 ( \t\t)。因此,您可以过滤掉包含以下任何内容的行:
grep -Ev $'^\t|\t\t|\t$' file
Run Code Online (Sandbox Code Playgroud)
如果可以有空格,事情就会变得更加复杂。如果您的字段可以以空格开头,请使用它(它认为只有空格的字段为空):
grep -Pv '\t\s*(\t|$)|\t$|^\t' file
Run Code Online (Sandbox Code Playgroud)
该更改会过滤掉与制表符匹配的行,后跟 0 个或多个空格,然后是另一个制表符或行尾。
如果最后一个字段只包含空格,这也会失败。为了避免这种情况,请使用perl和-F选项-a将输入拆分到@F数组中,告诉它打印,除非其中一个字段为空 ( /^$/):
perl -F'\t' -lane 'print unless grep{/^$/} @F' file
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5920 次 |
| 最近记录: |