「A」のすべての要素を含むが「B」の要素にはまったく含まれないリスト「C」が必要です。

「A」のすべての要素を含むが「B」の要素にはまったく含まれないリスト「C」が必要です。

2つのリストがあります。

より大きい「A」:

A=`echo -e '1\n2\n3\n4\n5'`
echo "$A"
1
2
3
4
5

より小さい「B」:

B=`echo -e '1\n2\n3'`
echo "$B"
1
2
3

尋ねる:しかし、「A」のすべての要素を含むが「B」は含まない3番目のリストが必要です。 bashでこれをどのように実行できますか?

echo "$C"
4
5

数字は「foo」から99まで可能です。

修正する:

シェルでは手動で動作しますが、スクリプトに入れると動作しないのでおかしいです!

cat a.txt 
A=$(seq 5)
B=$(seq 3)
comm -23 <(sort <<< "$A") <(sort <<< "$B")
sh a.txt 
a.txt: line 3: syntax error near unexpected token `('
a.txt: line 3: `comm -23 <(sort <<< "$A") <(sort <<< "$B")'

自家製動作します..:

A=$(seq 5)
B=$(seq 3)
comm -23 <(sort <<< "$A") <(sort <<< "$B")
4
5

なぜ?アップデートアップデート: "sh"の代わりにbashを使用する必要があります。 :D

答え1

これcomm必要なコマンドは次のとおりです。

$ A=$(seq 5)
$ B=$(seq 3)
$ comm -23 <(sort <<< "$A") <(sort <<< "$B")
4
5

これは入力をソートする必要がない方法です。これは、最初のファイルをメモリに読み込み、最初のファイルに基づいて2番目のファイルをフィルタリングするawkの一般的な慣用語です。ランダムデータを使ってみよう

$ A=$(seq 5 | sort -R); echo "$A"
3
5
1
2
4
$ B=$(seq 3 | sort -R); echo "$B"
2
1
3

出力は最初は5、その後は4になると予想されます。

$ awk 'NR==FNR {b[$1]=1; next} !($1 in b) {print}' <(echo "$B") <(echo "$A")
5
4

答え2

Glenn Jackmanが提供するように、このcommユーティリティはこれを行う最も簡単な方法です。ただし、この方法はソート順序を破壊します。

これを達成する別の方法は、元のソート順序を維持することです(両方のリストは同じ順序で事前ソートする必要があります)。

diff --unchanged-line-format '' --old-line-format '' file_a file_b

file_bこれにより、元の順序で一意のすべての行が返されます。
 

データセットが非常に大きい場合、これはより効率的であると信じています。ソート操作にはコストがかかる可能性があるためです。しかし、これは単なる推測です。

答え3

sort a b b | uniq -u

Hills(UNIX 7)よりも古いですが、まだ有効です。

答え4

またはPerlは次のようになります。

#!/usr/bin/perl -s
if($#ARGS == 0) {print "Usage: $0 -exclude=fileWithLinesToExclude [inputFile]\n"; exit(0)}
open(EXCL, $exclude);
%excluded = map { $_ => 1 } <EXCL>;
while(<>) {
   print $_ unless $excluded{$_};
} 

もの

  • perl -sスイッチが変数値になることを許可する
  • 咀嚼は発生せず、除外された行が「foobar_」で処理された行が「foobar」の場合は除外されません。
  • 可能なハッシュ挿入以外はソートされないため、処理されるファイルは必要なサイズやデータストリームなどにすることができます。
  • 入力ファイル名を渡すか、除外スイッチの後に入力をパイプします。

関連情報