ファイルにすべてのNULL値を含む列を表示しない方法

ファイルにすべてのNULL値を含む列を表示しない方法

たとえば、5つの列を持つファイルがあります(Sybase選択クエリの結果をリダイレクトして取得します)。各列はタブ文字で区切られます。すべてのNULL列をフィルタリングする必要があります。 5つの列のうちの1つでも空にすることができます。

たとえば、ファイルの列が次のような場合:

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

現在の値はすべての行を表示します!そして、柱を切る方法もわかりません。私はシェルスクリプトの初心者ですが、続行できません。

これを行う方法を提案できますか?

答え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(これが私がサブシェルを使用する理由です)、skip配列をコンマで区切られた値としてawk変数に渡します。これを使用して、split変数を配列に戻すことができますawk
  6. awks次に、配列の各番号を繰り返して列を空にするように設定し、残りを印刷します。

答え3

ファイルを2回処理しない限り、これを行うことはできません。まず、次のようにして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

関連情報