2016-08-31 13 views
1

bashの配列内の反復されない要素を見つける方法を探しています。Bash:配列内の反復されていない要素を見つける

簡単な例:

joined_arrays=(CVE-2015-4840 CVE-2015-4840 CVE-2015-4860 CVE-2015-4860 CVE-2016-3598) 
<magic> 
non_repeated=(CVE-2016-3598) 

コンテキストを与えるために、ここでの目標が原因であることに、ホスト上の「yumの更新」を介して、一般的に利用できないすべてのパッケージ更新のCVEの配列で終わることです除外される。私はそのようなことをやって思いついた方法は、3つの予備配列移入することです:

  • available_updatesを=()何yumのアップデートは「
  • all_updates =()#including除外したものを提供する#just
  • joined_updates =()#両方の以前の配列の内容 次に、joined_updates =()にロジックを適用し、正確に1回だけ含まれる要素だけを返します。 2回の出現を持つ要素は、通常どおり更新でき、 'excluded_updates =()'配列に終わる必要はありません。

これはうまくいけばいいと思います。私はそれを入力していたので、残ったものを除外された更新として残して、available_updates =()で見つかったすべての要素をall_updates =()から削除するほうが簡単かどうか疑問に思っています。

ありがとうございます!カウンタは正確に一つある

+0

あなたの目標は、などのセットの違い、交差点を、行うことができるのであれば、あなたは考えるかもしれません'comm'ユーティリティを使用します。 [BashFAQ#36](http://mywiki.wooledge.org/BashFAQ/036)を参照してください。 –

+0

@CharlesDuffy:実際に私はあなたの答えを見ませんでした。うーん。しかし、あなたは正しい、質問は別のものです:) – sjsam

答えて

2

一純bashのアプローチは、連想配列内のカウンタを記憶し、次にアイテムを探すことである。

declare -A seen=()     # create an associative array (requires bash 4) 
for item in "${joined_arrays[@]}"; do # iterate over original items 
    ((seen[$item] += 1))    # increment value associated with item 
done 

declare -a non_repeated=() 
for item in "${!seen[@]}"; do   # iterate over keys 
    if ((${seen[$item]} == 1)); then # if counter for that key is 1... 
    non_repeated+=("$item")   # ...add that item to the output array. 
done 

declare -p non_repeated    # print result 

他、terser(しかしbuggier - doesnの「Tは改行リテラルを含む値で動作)のアプローチは、標準的なテキスト操作ツールを利用することである。

non_repeated=()  # setup 

# use uniq -c to count; filter for results with a count of 1 
while read -r count value; do 
    ((count == 1)) && non_repeated+=("$value") 
done < <(printf '%s\n' "${joined_arrays[@]}" | sort | uniq -c) 

declare -p non_repeated # print result 

...または、さえterser(およびbuggier、配列値を分割することをint型を必要としますawkでのO正確に一つのフィールド):

readarray -t non_repeated \ 
    < <(printf '%s\n' "${joined_arrays[@]}" | sort | uniq -c | awk '$1 == 1 { print $2; }' 

が、私は本当にこれを使用して、誰からupvoteに値する@Aaron(から自分が出ているはずです答えをCRIBします。それはdoesn't-仕事と値-と-改行バグを保持していることに注意しない)、1にもuniq -uを使用することができます。

readarray -t non_repeated < <(printf '%s\n' "${joined_arrays[@]}" | sort | uniq -u) 
1

私はuniqに依存しています。

この正確なケースでは、ユニークな出現のみを出力するオプションが作成されています。これは、トークンのソートされた改行区切りリスト、IFSsortため、したがって必要とされ、入力に依存しています:

$ my_test_array=(1 2 3 2 1 0) 
$ printf '%s\n' "${my_test_array[@]}" | sort | uniq -u 
0 
3 
+0

* facepalm *。私はその可能性を忘れてしまったのは本当に恥ずかしいことです。(しかし、なぜ 'printf '%s \ n' 'ではなく' IFS'を扱うのですか?そういう意味では、 'echo'の非bash実装でシェルの動作に多大な余裕があります。 POSIXは、引数にバックスラッシュがあると、例えばエスケープの振る舞いを*定義しません。例えば、XSI拡張のものでない場合は、バックスラッシュエスケープシーケンス*を補間する必要があります。 –

+0

なぜ 'printf'ではなく' IFS'を扱うのですか?私は配列を持つ悩みで、働いた最初のことをしました。私は 'printf'を使う答えを更新しました。 – Aaron

+0

小さな更新をここで許してください - $ {foo [@]}" 'はバグを避けます(例えば、あなたの配列エントリのどれかに 'IFS'の文字が含まれている場合)。 –

関連する問題