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」の場合は除外されません。
- 可能なハッシュ挿入以外はソートされないため、処理されるファイルは必要なサイズやデータストリームなどにすることができます。
- 入力ファイル名を渡すか、除外スイッチの後に入力をパイプします。