如何不显示文件中包含所有 NULL 值的列

如何不显示文件中包含所有 NULL 值的列

我有一个文件,比方说,有 5 列(通过重定向 Sybase 选择查询的结果获得)。每列由制表符分隔。我需要过滤掉所有 NULL 的列。五列中的任何列都可以为空。

例如,如果文件中的列如下所示:

1000    NULL    NULL    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL
7       NULL    1000    2       NULL

输出必须是(删除第 2 列和第 5 列后),最好在同一个文件中:

1000    NULL    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2    
7       1000    2 

我到了:

for i in {1..5}  
do
echo $i
dlr="$"$i
str="{print $dlr}"
echo $str
awk '$str' <input_file> | while read value
    do
        echo $value

        if [ "$value" == "NULL" ]
        then
                echo "inside"
                cut $i 
        fi
    done
done

现在的值,显示所有行!另外,我不知道如何切断该列。我是一个 shell 脚本初学者,无法继续下去。

您能建议如何做到这一点吗?

答案1

借助于GNU实用程序datamash,首先反转行,然后删除所有空行并再次反转行:

$ datamash transpose | sed -Ee '/^(NULL\t)*NULL$/d' | datamash transpose 

答案2

我不太喜欢这个解决方案,但它似乎有效:

#!/bin/bash

input=~/tmp/input
skip=()

c=$(awk '{print NF;exit}' "$input")

for ((i=1;i<=c;i++)); do
    col=$(awk -v c="$i" '{print $c}' "$input" | sort -u)
    if [[ $col == NULL ]]; then
        skip+=( "$i" )
    fi
done
( IFS=,; awk -v S="${skip[*]}" '{ split(S,s,","); for (i=1;i<=length(s);i++) { $s[i]="" } print}' "$input" )
  1. input(您的输入文件)
  2. skip(稍后将填充的数组)
  3. c(将设置为文件中的列数。这假设整个文件具有统一的列数)
  4. 我们现在将循环遍历文件中的每一列,对其进行排序和唯一,并检查该列是否仅包含NULL.如果是这样,我们将该列号添加到skip数组中
  5. 现在,我们将 设为IFS逗号(这是我使用子 shell 的原因),并将数组skip作为逗号分隔值传递给awk变量。这样我们就可以用来split将该变量转换回数组awk
  6. awk然后将循环遍历s数组中的每个数字并将该列设置为空并打印剩余的内容。

答案3

如果不处理文件两次就无法做到这一点。首先使用以下命令awk构建最终cut命令:

killnulls(){
    cut -f "$(awk -F'\t' '
        { for(i=1;i<=NF;i++) a[i] += $i!="NULL" }
        END { for(i=1;i in a;i++) if(a[i]) printf j++?","i:i }
    ' "$@")" "$@"
}

$ killnulls file
1000    NULL    2
7       1000    2
7       1000    2
...

答案4

命令:

awk '/NULL/{gsub(/NULL/,"",$0);print $0}' filename| sed -r "s/\s+/ /g"| awk 'NR==1{$3=$2;$2="NULL";}1'

输出

awk '/NULL/{gsub(/NULL/,"",$0);print $0}' i.txt| sed -r "s/\s+/ /g"| awk 'NR==1{$3=$2;$2="NULL";}1'
1000 NULL 2
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2 
7 1000 2

相关内容