2016-12-30 52 views
2

我試圖隨機選擇一些數組的項目,然後更新它做一遍,直到最後一集:隨機選擇了N項從陣列和BASH更新SCRIPT

#! /bin/bash 

A=({1..27}) 
T=${#A[@]} #number of items in the array 
N=3 #number of items to be chosen 
V=$(($T/$N)) #number of times to loop 
echo ${A[@]} " >> ${#A[@]}" 
for ((n=0;n<$V;n++)); do 
    A1=() 
    for I in `shuf --input-range=0-$((${#A[*]} - 1)) | head -${N}`; do #random chooses N items random 
     S=`echo ${A[$I]}` #the chosen items 
     #echo $S 
     A1+=("$S|") #creates an array with the chosen items 
     A=("${A[@]/$S}") #deletes the the chosen items from array 
    done 
    echo ${A[@]} " >> ${#A[@]}" 
    echo ${A1[@]} " >> ${#A1[@]}" 
done 

類型輸出我得到這個代碼是:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 >> 27 
1 4 5 6 7 8 9 10 11 1 1 14 15 16 17 18 19 1 2 4 5 6 7 >> 27 
20| 2| 3| >> 3 
4 6 7 8 9 0 1 4 6 7 8 9 2 4 6 7 >> 27 
1| | 5| >> 3 
6 7 8 9 0 1 6 7 8 9 2 6 7 >> 27 
| | 4| >> 3 
7 8 9 0 1 7 8 9 2 7 >> 27 
6| | | >> 3 
7 8 9 0 1 7 8 9 7 >> 27 
| | 2| >> 3 
7 9 0 1 7 9 7 >> 27 
8| | | >> 3 
7 9 1 7 9 7 >> 27 
| | 0| >> 3 
7 9 1 7 9 7 >> 27 
| | | >> 3 
1 >> 27 
9| 7| | >> 3 

任何想法,爲什麼它在開始時工作正常,並在最後失敗?

+1

將來,在'#!/ bin // bash'行之後使用'set -x'在調試器模式下運行腳本。我非常多的根 - 導致它通過保持一個最小輸入爲'A =({1..5})'來使用它從數組'A'不適當的刪除。 – Inian

+1

也不要使用'for-loop'來處理命令輸出,適當地使用'IFS'並使用'while-loop'和進程替換 – Inian

回答

1

也有一些改進,可以給你的腳本進行:

  1. 使用小寫字母
  2. 引用您的擴展("${a[@]}")。
  3. 通過做unset a[j]刪除項目。
  4. a=("${a[@]}")重新構建陣列。
  5. 因爲shuf可以用-n產生一個計數結果,所以不需要頭部。
  6. 避免使用反引號,請改爲使用$(…)

,這將減少腳本:

#!/bin/bash 

t=27    #number of items in the array 
n=3     #number of items to be chosen 
a=($(seq 1 "$t")) 
a1=() 

while ((${#a[@]} >= n)); do 
    for j in $(shuf -n "$n" --input-range=0-$((${#a[@]}-1))); do # choose $n random items. 
     a1+=("${a[j]}")  # append to an array the chosen items. 
     unset "a[j]"   # deletes the the chosen items from array. 
    done 
    a=("${a[@]}")    # re-build the array. 
    echo "a ${a[@]} >> ${#a[@]}" 
    echo "a1 ${a1[@]} >> ${#a1[@]}" 
done 

這將產生這樣的輸出:

a 1 2 3 5 6 7 8 9 10 11 12 14 15 16 18 19 20 21 22 23 24 25 26 27 >> 24 
a1 17 13 4 >> 3 
a 1 2 5 6 7 8 10 11 12 14 15 16 18 19 20 21 22 23 24 26 27 >> 21 
a1 17 13 4 25 3 9 >> 6 
a 1 2 5 6 7 8 10 11 14 15 16 18 21 22 23 24 26 27 >> 18 
a1 17 13 4 25 3 9 12 20 19 >> 9 
a 1 2 5 7 8 10 11 14 15 16 21 22 24 26 27 >> 15 
a1 17 13 4 25 3 9 12 20 19 23 6 18 >> 12 
a 2 7 8 10 11 14 15 16 22 24 26 27 >> 12 
a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 >> 15 
a 2 8 10 14 15 22 24 26 27 >> 9 
a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 >> 18 
a 2 10 14 24 26 27 >> 6 
a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 >> 21 
a 14 26 27 >> 3 
a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 2 24 10 >> 24 
a >> 0 
a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 2 24 10 14 26 27 >> 27 

但在同一陣列A1可以建立只在一個步驟SHUF:

#!/bin/bash 

t=27        # number of items in the array 
n=3         # number of items to be chosen 
a1=($(shuf --input-range=1-"$t")) 
printf '%3s ' "${a1[@]}"; echo 

將打印:

$ ./script.sh 
15 23 1 9 24 2 21 11 12 10 19 25 27 13 5 26 4 7 14 3 22 20 17 18 16 6 8 

或者,如果結果必須在每行$n元素:

#!/bin/bash 

t=27         # number of items in the array 
n=3          # number of items to be chosen 
a1=($(shuf --input-range=1-"$t")) 

while ((i+n<=t)); do 
    printf '%3s ' "${a1[@]:i:n}"; echo 
    ((i+=n)) 
done 

印刷:

$ ./script.sh 
    7 19 16 
    4 20 26 
11 23 2 
13 6 15 
22 12 25 
18 14 10 
21 8 9 
    5 24 27 
    1 3 17 

看起來像一個簡單的解決方案。

+0

非常有見地的提示,謝謝。 – Roger

1

你的腳本中有一些錯誤的東西,特別是你(認爲你)從數組中刪除元素的方式。您並未刪除任何元素,只是在每個字段中用空字符串替換它們的值!。這就是爲什麼你的數組有27個元素,並且在第一次迭代之後,從每個字段中刪除所有的23。這裏有一個更地道的腳本:

#! /bin/bash 

a=({1..27}) 
n=3 #number of items to be chosen 
while ((${#a[@]}>=n)); do 
    a1=() 
    for ((i=0;i<n;++i)); do 
     # pick an index 
     x=$((RANDOM%${#a[@]})) 
     # append its value to array a1 
     a1+=("${a[x]}") 
     # unset it 
     unset 'a[x]' 
     # reconstruct array a (make it non-sparse again) 
     a=("${a[@]}") 
    done 
    # print array 
    printf 'a: %s >> %s\n' "${a[*]}" "${#a[@]}" 
    # print chosen elements 
    printf 'a1: %s >> %s\n' "${a1[*]}" "${#a1[@]}" 
done 
+0

這個腳本有幾個錯誤的想法。一:隨機數x不是均勻分佈的。變量RANDOM生成0-32767範圍內的整數。對於平均每32768次抽獎,RANDOM%100將在0-67範圍內產生328個結果,在68-99範圍內產生327個結果。這顯然是一種非均勻的隨機分佈。 – sorontar

+0

可以用一個簡單的循環使x的值統一:'range = 27; a = $ RANDOM;直到((a <(32767 /範圍)*範圍));做a = $ RANDOM;完成;回聲「a = $ a x = $((a%範圍))」'。但是:爲什麼這是shuf可以在一個簡單的調用中做同樣的事情:'x = $(shuf -i 0-27 -n 1)'。 – sorontar

+0

當然,RANDOM和shuf都適用於簡單的隨機要求。如果需要CSPRNG,則可能是[簡單](http://security.stackexchange.com/a/44377/126077)'printf'%d \ n'「0x $(openssl rand -hex 4)」'(32如果不是,簡單地調用urandom肯定會:'printf'%d \ n'「0x $(dd if =/dev/urandom bs = 1 count = 4 2>/dev/null | xxd -p)「'(同樣是一個32位十進制數)。 – sorontar